PluginProbe
WPSSO Core – Complete Schema Markup and Meta Tags / 22.7.0
WPSSO Core – Complete Schema Markup and Meta Tags v22.7.0
22.7.0 22.6.1 22.6.0 22.5.3 22.5.2 22.5.1 22.4.0 22.3.0 22.2.1 22.2.0 22.1.3 22.1.2 22.1.1 22.1.0 22.0.0 21.13.3 21.13.2 trunk 21.13.1
← All changes | lib/com/util.php +2706 -0 22.5.222.7.0 View file →
@@ -1,0 +1,2706 @@
1 +<?php
2 +/*
3 + * License: GPLv3
4 + * License URI: https://www.gnu.org/licenses/gpl.txt
5 + * Copyright 2012-2026 Jean-Sebastien Morisset (https://surniaulula.com/)
6 + */
7 +
8 +if ( ! defined( 'ABSPATH' ) ) {
9 +
10 + die( 'These aren\'t the droids you\'re looking for.' );
11 +}
12 +
13 +if ( ! class_exists( 'SucomUtil' ) ) {
14 +
15 + class SucomUtil {
16 +
17 + protected static $url_clean_query = array(
18 +
19 + // Age Verify plugin:
20 + 'age-verified',
21 +
22 + // Autoptimize:
23 + 'ao_noptimize',
24 +
25 + // AMP:
26 + 'usqp',
27 +
28 + // Cookie Notice:
29 + 'cn-reloaded',
30 +
31 + // ShareASale:
32 + 'sscid',
33 +
34 + // Adobe Advertising Cloud:
35 + 'ef_id',
36 +
37 + // Adobe Analytics:
38 + 's_kwcid',
39 +
40 + // Bronto:
41 + '_bta_tid',
42 + '_bta_c',
43 +
44 + // Dotdigital:
45 + 'dm_i',
46 +
47 + // Facebook:
48 + 'fb_action_ids',
49 + 'fb_action_types',
50 + 'fb_source',
51 + 'fbclid',
52 +
53 + // Google Analytics and Ads:
54 + 'utm_source',
55 + 'utm_campaign',
56 + 'utm_medium',
57 + 'utm_expid',
58 + 'utm_term',
59 + 'utm_content',
60 + '_ga',
61 + 'gclid',
62 + 'campaignid',
63 + 'adgroupid',
64 + 'adid',
65 + 'gbraid',
66 + 'wbraid',
67 +
68 + // Google Web Stories:
69 + '_gl',
70 +
71 + // Google DoubleClick:
72 + 'gclsrc',
73 +
74 + // GoDataFeed:
75 + 'gdfms',
76 + 'gdftrk',
77 + 'gdffi',
78 +
79 + // Klaviyo
80 + '_ke',
81 +
82 + // Listrak:
83 + 'trk_contact',
84 + 'trk_msg',
85 + 'trk_module',
86 + 'trk_sid',
87 +
88 + // Mailchimp:
89 + 'mc_cid',
90 + 'mc_eid',
91 +
92 + // Marin:
93 + 'mkwid',
94 + 'pcrid',
95 +
96 + // Matomo:
97 + 'mtm_source',
98 + 'mtm_medium',
99 + 'mtm_campaign',
100 + 'mtm_keyword',
101 + 'mtm_cid',
102 + 'mtm_content',
103 +
104 + // Microsoft Advertising:
105 + 'msclkid',
106 +
107 + // Pinterest:
108 + 'epik',
109 + 'pp',
110 +
111 + // Piwik Pro:
112 + 'pk_source',
113 + 'pk_medium',
114 + 'pk_campaign',
115 + 'pk_keyword',
116 + 'pk_cid',
117 + 'pk_content',
118 +
119 + // Springbot:
120 + 'redirect_log_mongo_id',
121 + 'redirect_mongo_id',
122 + 'sb_referer_host',
123 +
124 + // WordPress:
125 + 'doing_wp_cron',
126 + );
127 +
128 + protected static $publisher_languages = array(
129 +
130 + /*
131 + * https://developers.facebook.com/docs/messenger-platform/messenger-profile/supported-locales
132 + */
133 + 'facebook' => array(
134 + 'af_ZA' => 'Afrikaans',
135 + 'ar_AR' => 'Arabic',
136 + 'as_IN' => 'Assamese',
137 + 'az_AZ' => 'Azerbaijani',
138 + 'be_BY' => 'Belarusian',
139 + 'bg_BG' => 'Bulgarian',
140 + 'bn_IN' => 'Bengali',
141 + 'br_FR' => 'Breton',
142 + 'bs_BA' => 'Bosnian',
143 + 'ca_ES' => 'Catalan',
144 + 'cb_IQ' => 'Sorani Kurdish',
145 + 'co_FR' => 'Corsican',
146 + 'cs_CZ' => 'Czech',
147 + 'cx_PH' => 'Cebuano',
148 + 'cy_GB' => 'Welsh',
149 + 'da_DK' => 'Danish',
150 + 'de_DE' => 'German',
151 + 'el_GR' => 'Greek',
152 + 'en_GB' => 'English (UK)',
153 + 'en_UD' => 'English (Upside Down)',
154 + 'en_US' => 'English (US)',
155 + 'es_ES' => 'Spanish (Spain)',
156 + 'es_LA' => 'Spanish',
157 + 'et_EE' => 'Estonian',
158 + 'eu_ES' => 'Basque',
159 + 'fa_IR' => 'Persian',
160 + 'ff_NG' => 'Fulah',
161 + 'fi_FI' => 'Finnish',
162 + 'fo_FO' => 'Faroese',
163 + 'fr_CA' => 'French (Canada)',
164 + 'fr_FR' => 'French (France)',
165 + 'fy_NL' => 'Frisian',
166 + 'ga_IE' => 'Irish',
167 + 'gl_ES' => 'Galician',
168 + 'gn_PY' => 'Guarani',
169 + 'gu_IN' => 'Gujarati',
170 + 'ha_NG' => 'Hausa',
171 + 'he_IL' => 'Hebrew',
172 + 'hi_IN' => 'Hindi',
173 + 'hr_HR' => 'Croatian',
174 + 'hu_HU' => 'Hungarian',
175 + 'hy_AM' => 'Armenian',
176 + 'id_ID' => 'Indonesian',
177 + 'is_IS' => 'Icelandic',
178 + 'it_IT' => 'Italian',
179 + 'ja_JP' => 'Japanese',
180 + 'ja_KS' => 'Japanese (Kansai)',
181 + 'jv_ID' => 'Javanese',
182 + 'ka_GE' => 'Georgian',
183 + 'kk_KZ' => 'Kazakh',
184 + 'km_KH' => 'Khmer',
185 + 'kn_IN' => 'Kannada',
186 + 'ko_KR' => 'Korean',
187 + 'ku_TR' => 'Kurdish (Kurmanji)',
188 + 'lt_LT' => 'Lithuanian',
189 + 'lv_LV' => 'Latvian',
190 + 'mg_MG' => 'Malagasy',
191 + 'mk_MK' => 'Macedonian',
192 + 'ml_IN' => 'Malayalam',
193 + 'mn_MN' => 'Mongolian',
194 + 'mr_IN' => 'Marathi',
195 + 'ms_MY' => 'Malay',
196 + 'mt_MT' => 'Maltese',
197 + 'my_MM' => 'Burmese',
198 + 'nb_NO' => 'Norwegian (bokmal)',
199 + 'ne_NP' => 'Nepali',
200 + 'nl_BE' => 'Dutch (België)',
201 + 'nl_NL' => 'Dutch',
202 + 'nn_NO' => 'Norwegian (nynorsk)',
203 + 'or_IN' => 'Oriya',
204 + 'pa_IN' => 'Punjabi',
205 + 'pl_PL' => 'Polish',
206 + 'ps_AF' => 'Pashto',
207 + 'pt_BR' => 'Portuguese (Brazil)',
208 + 'pt_PT' => 'Portuguese (Portugal)',
209 + 'ro_RO' => 'Romanian',
210 + 'ru_RU' => 'Russian',
211 + 'rw_RW' => 'Kinyarwanda',
212 + 'sc_IT' => 'Sardinian',
213 + 'si_LK' => 'Sinhala',
214 + 'sk_SK' => 'Slovak',
215 + 'sl_SI' => 'Slovenian',
216 + 'so_SO' => 'Somali',
217 + 'sq_AL' => 'Albanian',
218 + 'sr_RS' => 'Serbian',
219 + 'sv_SE' => 'Swedish',
220 + 'sw_KE' => 'Swahili',
221 + 'sz_PL' => 'Silesian',
222 + 'ta_IN' => 'Tamil',
223 + 'te_IN' => 'Telugu',
224 + 'tg_TJ' => 'Tajik',
225 + 'th_TH' => 'Thai',
226 + 'tl_PH' => 'Filipino',
227 + 'tr_TR' => 'Turkish',
228 + 'tz_MA' => 'Tamazight',
229 + 'uk_UA' => 'Ukrainian',
230 + 'ur_PK' => 'Urdu',
231 + 'uz_UZ' => 'Uzbek',
232 + 'vi_VN' => 'Vietnamese',
233 + 'zh_CN' => 'Simplified Chinese (China)',
234 + 'zh_HK' => 'Traditional Chinese (Hong Kong)',
235 + 'zh_TW' => 'Traditional Chinese (Taiwan)',
236 + ),
237 +
238 + /*
239 + * https://developers.google.com/+/web/api/supported-languages
240 + */
241 + 'google' => array(
242 + 'af' => 'Afrikaans',
243 + 'am' => 'Amharic',
244 + 'ar' => 'Arabic',
245 + 'eu' => 'Basque',
246 + 'bn' => 'Bengali',
247 + 'bg' => 'Bulgarian',
248 + 'ca' => 'Catalan',
249 + 'zh-CN' => 'Chinese (Simplified)',
250 + 'zh-HK' => 'Chinese (Hong Kong)',
251 + 'zh-TW' => 'Chinese (Traditional)',
252 + 'hr' => 'Croatian',
253 + 'cs' => 'Czech',
254 + 'da' => 'Danish',
255 + 'nl' => 'Dutch',
256 + 'en-GB' => 'English (UK)',
257 + 'en-US' => 'English (US)',
258 + 'et' => 'Estonian',
259 + 'fil' => 'Filipino',
260 + 'fi' => 'Finnish',
261 + 'fr' => 'French',
262 + 'fr-CA' => 'French (Canadian)',
263 + 'gl' => 'Galician',
264 + 'de' => 'German',
265 + 'el' => 'Greek',
266 + 'gu' => 'Gujarati',
267 + 'iw' => 'Hebrew',
268 + 'hi' => 'Hindi',
269 + 'hu' => 'Hungarian',
270 + 'is' => 'Icelandic',
271 + 'id' => 'Indonesian',
272 + 'it' => 'Italian',
273 + 'ja' => 'Japanese',
274 + 'kn' => 'Kannada',
275 + 'ko' => 'Korean',
276 + 'lv' => 'Latvian',
277 + 'lt' => 'Lithuanian',
278 + 'ms' => 'Malay',
279 + 'ml' => 'Malayalam',
280 + 'mr' => 'Marathi',
281 + 'no' => 'Norwegian',
282 + 'fa' => 'Persian',
283 + 'pl' => 'Polish',
284 + 'pt-BR' => 'Portuguese (Brazil)',
285 + 'pt-PT' => 'Portuguese (Portugal)',
286 + 'ro' => 'Romanian',
287 + 'ru' => 'Russian',
288 + 'sr' => 'Serbian',
289 + 'sk' => 'Slovak',
290 + 'sl' => 'Slovenian',
291 + 'es' => 'Spanish',
292 + 'es-419' => 'Spanish (Latin America)',
293 + 'sw' => 'Swahili',
294 + 'sv' => 'Swedish',
295 + 'ta' => 'Tamil',
296 + 'te' => 'Telugu',
297 + 'th' => 'Thai',
298 + 'tr' => 'Turkish',
299 + 'uk' => 'Ukrainian',
300 + 'ur' => 'Urdu',
301 + 'vi' => 'Vietnamese',
302 + 'zu' => 'Zulu',
303 + ),
304 + 'pinterest' => array(
305 + 'en' => 'English',
306 + 'ja' => 'Japanese',
307 + ),
308 +
309 + /*
310 + * https://dev.twitter.com/web/overview/languages
311 + */
312 + 'twitter' => array(
313 + 'ar' => 'Arabic',
314 + 'bn' => 'Bengali',
315 + 'zh-tw' => 'Chinese (Traditional)',
316 + 'zh-cn' => 'Chinese (Simplified)',
317 + 'cs' => 'Czech',
318 + 'da' => 'Danish',
319 + 'en' => 'English',
320 + 'de' => 'German',
321 + 'el' => 'Greek',
322 + 'fi' => 'Finnish',
323 + 'fil' => 'Filipino',
324 + 'fr' => 'French',
325 + 'he' => 'Hebrew',
326 + 'hi' => 'Hindi',
327 + 'hu' => 'Hungarian',
328 + 'id' => 'Indonesian',
329 + 'it' => 'Italian',
330 + 'ja' => 'Japanese',
331 + 'ko' => 'Korean',
332 + 'msa' => 'Malay',
333 + 'nl' => 'Dutch',
334 + 'no' => 'Norwegian',
335 + 'fa' => 'Persian',
336 + 'pl' => 'Polish',
337 + 'pt' => 'Portuguese',
338 + 'ro' => 'Romanian',
339 + 'ru' => 'Russian',
340 + 'es' => 'Spanish',
341 + 'sv' => 'Swedish',
342 + 'th' => 'Thai',
343 + 'tr' => 'Turkish',
344 + 'uk' => 'Ukrainian',
345 + 'ur' => 'Urdu',
346 + 'vi' => 'Vietnamese',
347 + )
348 + );
349 +
350 + public function __construct() {}
351 +
352 + /*
353 + * ARRAY HANDLING METHODS:
354 + *
355 + * add_after_key()
356 + * add_before_key()
357 + * add_multi_values()
358 + * array_count_diff()
359 + * array_flatten()
360 + * array_implode()
361 + * array_insert_element()
362 + * array_key_last()
363 + * array_map_recursive()
364 + * array_maybe_unserialize()
365 + * array_merge_recursive_distinct()
366 + * array_slice_fifo()
367 + * array_to_hashtags()
368 + * array_to_keywords()
369 + * get_array_or_element()
370 + * get_array_pretty()
371 + * get_assoc_salt()
372 + * get_multi_values()
373 + * move_to_front()
374 + * move_to_end()
375 + * natasort()
376 + * natksort()
377 + * next_key()
378 + * preg_grep_keys()
379 + * unset_keys()
380 + * unset_numeric_keys()
381 + *
382 + * Modify the referenced array and return true or false.
383 + */
384 + public static function add_after_key( array &$arr, $match_key, $arr_or_key, $value = null ) {
385 +
386 + return self::array_insert_element( $arr, $insert = 'after', $match_key, $arr_or_key, $value );
387 + }
388 +
389 + /*
390 + * Modify the referenced array and return true or false.
391 + */
392 + public static function add_before_key( array &$arr, $match_key, $arr_or_key, $value = null ) {
393 +
394 + return self::array_insert_element( $arr, $insert = 'before', $match_key, $arr_or_key, $value );
395 + }
396 +
397 + /*
398 + * Add an array of values that have a common numbered prefix key.
399 + */
400 + public static function add_multi_values( array &$opts, $opt_pre, $new_key = null ) {
401 +
402 + if ( null === $new_key ) $new_key = $opt_pre;
403 +
404 + $opts[ $new_key ] = self::get_multi_values( $opts, $opt_pre );
405 + }
406 +
407 + public static function array_count_diff( array $arr, $max = 0 ) {
408 +
409 + $diff = 0;
410 +
411 + if ( $max > 0 && $max >= count( $arr ) ) {
412 +
413 + $diff = $max - count( $arr );
414 + }
415 +
416 + return $diff;
417 + }
418 +
419 + /*
420 + * Convert a multi-dimentional array to a single dimension array.
421 + */
422 + public static function array_flatten( array $arr ) {
423 +
424 + $flattened = array();
425 +
426 + foreach ( $arr as $key => $value ) {
427 +
428 + if ( is_array( $value ) ) {
429 +
430 + $flattened = array_merge( $flattened, self::array_flatten( $value ) );
431 +
432 + } else $flattened[ $key ] = $value;
433 + }
434 +
435 + return $flattened;
436 + }
437 +
438 + /*
439 + * Implode multi-dimentional array.
440 + */
441 + public static function array_implode( array $arr, $glue = ' ' ) {
442 +
443 + $imploded = '';
444 +
445 + foreach ( $arr as $value ) {
446 +
447 + if ( is_array( $value ) ) {
448 +
449 + $imploded .= self::array_implode( $value, $glue ) . $glue;
450 +
451 + } else $imploded .= $value . $glue;
452 + }
453 +
454 + return strlen( $glue ) ? rtrim( $imploded, $glue ) : $glue;
455 + }
456 +
457 + /*
458 + * Modify the referenced array and return true or false.
459 + */
460 + public static function array_insert_element( array &$arr, $insert, $match_key, $arr_or_key, $value = null ) {
461 +
462 + $found_match = false;
463 +
464 + if ( array_key_exists( $match_key, $arr ) ) {
465 +
466 + $new_arr = array();
467 +
468 + foreach ( $arr as $key => $val ) {
469 +
470 + if ( 'after' === $insert ) {
471 +
472 + $new_arr[ $key ] = $val;
473 + }
474 +
475 + /*
476 + * Add new value before/after the matched key.
477 + *
478 + * Replace the matched key by default (no test required).
479 + */
480 + if ( $key === $match_key ) {
481 +
482 + if ( is_array( $arr_or_key ) ) {
483 +
484 + $new_arr = array_merge( $new_arr, $arr_or_key );
485 +
486 + } elseif ( is_string( $arr_or_key ) ) {
487 +
488 + $new_arr[ $arr_or_key ] = $value;
489 +
490 + } else $new_arr[] = $value;
491 +
492 + $found_match = true;
493 + }
494 +
495 + if ( 'before' === $insert ) {
496 +
497 + $new_arr[ $key ] = $val;
498 + }
499 + }
500 +
501 + $arr = $new_arr;
502 +
503 + unset( $new_arr );
504 + }
505 +
506 + return $found_match;
507 + }
508 +
509 + public static function array_key_last( array $array ) {
510 +
511 + if ( function_exists( 'array_key_last' ) ) {
512 +
513 + return array_key_last( $array ); // Since PHP v7.3.
514 + }
515 +
516 + return key( array_slice( $array, -1, 1, true ) );
517 + }
518 +
519 + public static function array_map_recursive( $func, array $arr ) {
520 +
521 + foreach ( $arr as $key => $el ) {
522 +
523 + $arr[ $key ] = is_array( $el ) ? self::array_map_recursive( $func, $el ) : $func( $el );
524 + }
525 +
526 + return $arr;
527 + }
528 +
529 + public static function array_maybe_unserialize( array $arr ) {
530 +
531 + return self::array_map_recursive( 'maybe_unserialize', $arr );
532 + }
533 +
534 + /*
535 + * PHP's array_merge_recursive() merges arrays, but it converts values with duplicate keys to arrays rather than
536 + * overwriting the value in the first array with the duplicate value in the second array, as array_merge does. The
537 + * following method does not change the datatypes of the values in the arrays. Matching key values in the second
538 + * array overwrite those in the first array, as is the case with array_merge().
539 + */
540 + public static function array_merge_recursive_distinct( array &$arr1, array &$arr2 ) {
541 +
542 + $merged = $arr1;
543 +
544 + foreach ( $arr2 as $key => &$value ) {
545 +
546 + if ( is_array( $value ) && isset( $merged[ $key ] ) && is_array( $merged[ $key ] ) ) {
547 +
548 + $merged[ $key ] = self::array_merge_recursive_distinct( $merged[ $key ], $value );
549 +
550 + } else $merged[ $key ] = $value;
551 + }
552 +
553 + return $merged;
554 + }
555 +
556 + /*
557 + * Maybe limit the number of array elements.
558 + */
559 + public static function array_slice_fifo( array $array, $max = 1 ) {
560 +
561 + if ( ! empty( $array ) && is_numeric( $max ) && $max > 0 && count( $array ) > $max ) {
562 +
563 + return array_slice( $array, -$max, $length = null, $preserve_keys = true );
564 + }
565 +
566 + return $array;
567 + }
568 +
569 + public static function array_to_hashtags( array $arr = array() ) {
570 +
571 + $hashtags = self::sanitize_hashtags( $arr );
572 + $hashtags = array_filter( $hashtags ); // Removes empty array elements.
573 + $hashtags = trim( implode( $glue = ' ', $hashtags ) );
574 +
575 + return $hashtags;
576 + }
577 +
578 + /*
579 + * Convert an array to a comma delimited text string.
580 + */
581 + public static function array_to_keywords( array $arr = array() ) {
582 +
583 + $keywords = array_map( 'sanitize_text_field', $arr );
584 + $keywords = trim( implode( $glue = ', ', $keywords ) );
585 +
586 + return $keywords;
587 + }
588 +
589 + /*
590 + * Convert an array to an HTML list.
591 + */
592 + public static function array_to_list_html( array $arr, $type = 'ul' ) {
593 +
594 + return '<' . $type . '><li>' . implode( $glue = '</li> <li>', $arr ) . '</li></' . $type . '> ';
595 + }
596 +
597 + public static function get_array_or_element( $arr, $key = false, $add_none = false ) {
598 +
599 + if ( null === $key ) {
600 +
601 + // Nothing to do.
602 +
603 + } elseif ( false === $key ) {
604 +
605 + // Nothing to do.
606 +
607 + } elseif ( true === $key ) { // Sort elements.
608 +
609 + asort( $arr ); // Sort an array in ascending order and maintain index association.
610 +
611 + } elseif ( isset( $arr[ $key ] ) ) { // Return a specific array element.
612 +
613 + return $arr[ $key ];
614 +
615 + } else return null; // Array key not found - return null.
616 +
617 + if ( true === $add_none ) { // Prefix array with 'none'.
618 +
619 + /*
620 + * The union operator (+) gives priority to values in the first array, while
621 + * array_replace() gives priority to values in the the second array.
622 + */
623 + $arr = array( 'none' => 'none' ) + $arr; // Maintains numeric index.
624 + }
625 +
626 + return $arr;
627 + }
628 +
629 + public static function get_array_parents( array $arr, $parent_key = '', $gparent_key = '', &$parents = array() ) {
630 +
631 + foreach ( $arr as $child_key => $value ) {
632 +
633 + if ( is_array( $value ) ) {
634 +
635 + self::get_array_parents( $value, $child_key, $parent_key, $parents );
636 +
637 + } elseif ( $parent_key && $child_key !== $parent_key ) {
638 +
639 + $parents[ $child_key ][] = $parent_key;
640 +
641 + } elseif ( $gparent_key && $child_key === $parent_key ) {
642 +
643 + $parents[ $child_key ][] = $gparent_key;
644 + }
645 + }
646 +
647 + return $parents;
648 + }
649 +
650 + public static function get_array_pretty( $mixed, $flatten = false ) {
651 +
652 + $pretty = '';
653 +
654 + if ( is_array( $mixed ) ) {
655 +
656 + foreach ( $mixed as $key => $val ) {
657 +
658 + $val = self::get_array_pretty( $val, $flatten );
659 +
660 + if ( $flatten ) {
661 +
662 + $pretty .= $key . '=' . $val.', ';
663 +
664 + } else {
665 +
666 + if ( is_object( $mixed[ $key ] ) ) {
667 +
668 + unset( $mixed[ $key ] ); // Dereference the object first.
669 + }
670 +
671 + $mixed[ $key ] = $val;
672 + }
673 + }
674 +
675 + $pretty = $flatten ? '(' . trim( $pretty, ', ' ) . ')' : $mixed;
676 +
677 + } elseif ( false === $mixed ) {
678 +
679 + $pretty = 'false';
680 +
681 + } elseif ( true === $mixed ) {
682 +
683 + $pretty = 'true';
684 +
685 + } elseif ( null === $mixed ) {
686 +
687 + $pretty = 'null';
688 +
689 + } elseif ( '' === $mixed ) {
690 +
691 + $pretty = '\'\'';
692 +
693 + } elseif ( is_object( $mixed ) ) {
694 +
695 + $pretty = 'object ' . get_class( $mixed );
696 +
697 + } else $pretty = $mixed;
698 +
699 + return $pretty;
700 + }
701 +
702 + public static function get_assoc_salt( array $assoc ) {
703 +
704 + $assoc_salt = '';
705 +
706 + foreach ( $assoc as $key => $val ) {
707 +
708 + $assoc_salt .= '-' . $key . ':' . (string) $val;
709 + }
710 +
711 + $assoc_salt = ltrim( $assoc_salt, '-' );
712 +
713 + return $assoc_salt;
714 + }
715 +
716 + /*
717 + * Return a indexed array of values that have a common prefix key.
718 + */
719 + public static function get_multi_values( array &$opts, $opt_pre ) {
720 +
721 + $values = self::preg_grep_keys( '/^' . $opt_pre . '_([0-9]+)$/', $opts, $invert = false, $replace = '$1' );
722 +
723 + foreach ( $values as $num => $val ) {
724 +
725 + if ( ! self::is_valid_option_value( $val ) ) { // Allow for 0 but not empty string.
726 +
727 + unset( $values[ $num ] );
728 + }
729 + }
730 +
731 + return $values;
732 + }
733 +
734 + /*
735 + * Move an array element to the front.
736 + */
737 + public static function move_to_front( array &$arr, $key ) {
738 +
739 + if ( array_key_exists( $key, $arr ) ) {
740 +
741 + $val = $arr[ $key ];
742 +
743 + unset( $arr[ $key ] );
744 +
745 + $arr = array_merge( array( $key => $val ), $arr );
746 + }
747 +
748 + return $arr;
749 + }
750 +
751 + /*
752 + * Move an array element to the end.
753 + */
754 + public static function move_to_end( array &$arr, $key ) {
755 +
756 + if ( array_key_exists( $key, $arr ) ) {
757 +
758 + $val = $arr[ $key ];
759 +
760 + unset( $arr[ $key ] );
761 +
762 + $arr[ $key ] = $val;
763 + }
764 +
765 + return $arr;
766 + }
767 +
768 + public static function natasort( array &$arr ) {
769 +
770 + if ( function_exists( 'remove_accents' ) ) { // WordPress function.
771 +
772 + return uasort( $arr, array( __CLASS__, 'strnatcasecmp_remove_accents' ) );
773 + }
774 +
775 + return uasort( $arr, 'strnatcasecmp' );
776 + }
777 +
778 + public static function natksort( array &$arr ) {
779 +
780 + if ( function_exists( 'remove_accents' ) ) { // WordPress function.
781 +
782 + return uksort( $arr, array( __CLASS__, 'strnatcasecmp_remove_accents' ) );
783 + }
784 +
785 + return uksort( $arr, 'strnatcasecmp' );
786 + }
787 +
788 + public static function next_key( $needle, array &$arr, $loop_around = true ) {
789 +
790 + $keys = array_keys( $arr );
791 + $pos = array_search( $needle, $keys );
792 +
793 + if ( false !== $pos ) {
794 +
795 + if ( isset( $keys[ $pos + 1 ] ) ) {
796 +
797 + return $keys[ $pos + 1 ];
798 +
799 + } elseif ( true === $loop_around ) {
800 +
801 + return $keys[ 0 ];
802 + }
803 + }
804 +
805 + return false;
806 + }
807 +
808 + /*
809 + * $keys_preg must be a string.
810 + *
811 + * $replace can be a string or an associative array of 'pattern' => 'replacement'.
812 + */
813 + public static function preg_grep_keys( $keys_preg, $in_array, $invert = false, $replace = false ) {
814 +
815 + if ( ! is_array( $in_array ) || empty( $in_array ) ) { // Just in case.
816 +
817 + return array();
818 + }
819 +
820 + $in_array_keys = array_keys( $in_array );
821 + $matched_keys = preg_grep( $keys_preg, $in_array_keys, $invert ? PREG_GREP_INVERT : 0 );
822 +
823 + if ( empty( $matched_keys ) && $invert ) { // Nothing to do.
824 +
825 + return $in_array;
826 + }
827 +
828 + /*
829 + * The $replace value can be a string or an associative array of 'pattern' => 'replacement'.
830 + */
831 + if ( is_array( $replace ) ) {
832 +
833 + $patterns = array_keys( $replace );
834 + $replacements = array_values( $replace );
835 +
836 + } else {
837 +
838 + $patterns = $keys_preg;
839 + $replacements = $replace;
840 + }
841 +
842 + $out_array = array();
843 +
844 + foreach ( $matched_keys as $key ) {
845 +
846 + if ( false === $replace ) { // Element key remains unchanged.
847 +
848 + $out_array[ $key ] = $in_array[ $key ];
849 +
850 + } else {
851 +
852 + $fixed = preg_replace( $patterns, $replacements, $key );
853 +
854 + $out_array[ $fixed ] = $in_array[ $key ];
855 + }
856 + }
857 +
858 + return $out_array;
859 + }
860 +
861 + public static function unset_keys( &$arr1, $arr2 ) {
862 +
863 + foreach ( array_keys( $arr2 ) as $key ) {
864 +
865 + unset( $arr1[ $key ] );
866 + }
867 + }
868 +
869 + public static function unset_numeric_keys( &$arr ) {
870 +
871 + foreach ( array_keys( $arr ) as $key ) {
872 +
873 + if ( is_numeric( $key ) ) {
874 +
875 + unset( $arr[ $key ] );
876 + }
877 + }
878 + }
879 +
880 + /*
881 + * COUNTRY METHODS:
882 + *
883 + * get_alpha2_countries()
884 + * get_alpha2_country_name()
885 + */
886 + public static function get_alpha2_countries() {
887 +
888 + if ( ! class_exists( 'SucomCountryCodes' ) ) {
889 +
890 + require_once dirname( __FILE__ ) . '/country-codes.php';
891 + }
892 +
893 + return SucomCountryCodes::get( 'alpha2' );
894 + }
895 +
896 + public static function get_alpha2_country_name( $country_code, $default_code = false ) {
897 +
898 + if ( empty( $country_code ) || 'none' === $country_code ) {
899 +
900 + return false;
901 + }
902 +
903 + if ( ! class_exists( 'SucomCountryCodes' ) ) {
904 +
905 + require_once dirname( __FILE__ ) . '/country-codes.php';
906 + }
907 +
908 + $countries = SucomCountryCodes::get( 'alpha2' );
909 +
910 + if ( ! isset( $countries[ $country_code ] ) ) {
911 +
912 + if ( false === $default_code || ! isset( $countries[ $default_code ] ) ) {
913 +
914 + return false;
915 + }
916 +
917 + return $countries[ $default_code ];
918 + }
919 +
920 + return $countries[ $country_code ];
921 + }
922 +
923 + /*
924 + * CURRENCY METHODS:
925 + *
926 + * get_currencies()
927 + * get_currencies_abbrev()
928 + * get_currency_symbol_abbrev()
929 + *
930 + * Used by WpssoSubmenuGeneral->get_table_rows() for 'Default Currency' option.
931 + */
932 + public static function get_currencies( $key = false, $add_none = false, $format = '%2$s (%1$s)' ) {
933 +
934 + if ( ! class_exists( 'SucomCurrencies' ) ) {
935 +
936 + require_once dirname( __FILE__ ) . '/currencies.php';
937 + }
938 +
939 + if ( is_string( $key ) ) {
940 +
941 + return SucomCurrencies::get( $key, $format );
942 + }
943 +
944 + return self::get_array_or_element( SucomCurrencies::get( null, $format ), $key, $add_none );
945 + }
946 +
947 + public static function get_currencies_abbrev() {
948 +
949 + $currencies_by_abbrev = self::get_currencies( null, $add_none = false, $format = '%1$s' );
950 +
951 + asort( $currencies_by_abbrev ); // Sort by abbreviation.
952 +
953 + return $currencies_by_abbrev;
954 + }
955 +
956 + public static function get_currency_symbol_abbrev( $symbol = false, $default = 'USD', $decode = true ) {
957 +
958 + if ( $decode ) $symbol = self::decode_html( $symbol );
959 +
960 + if ( $symbol === '$' ) return 'USD';
961 +
962 + if ( ! class_exists( 'SucomCurrencies' ) ) {
963 +
964 + require_once dirname( __FILE__ ) . '/currencies.php';
965 + }
966 +
967 + $currencies_by_abbrev = SucomCurrencies::get_symbols( $key = null, $decode );
968 +
969 + $currencies_by_symbol = array_flip( $currencies_by_abbrev ); // Index by symbol.
970 +
971 + unset( $currencies_by_abbrev );
972 +
973 + return isset( $currencies_by_symbol[ $symbol ] ) ? $currencies_by_symbol[ $symbol ] : false;
974 + }
975 +
976 + /*
977 + * DASHICON METHODS:
978 + */
979 + public static function get_dashicons( $key = true, $add_none = false ) {
980 +
981 + if ( ! class_exists( 'SucomDashicons' ) ) {
982 +
983 + require_once dirname( __FILE__ ) . '/dashicons.php';
984 + }
985 +
986 + if ( is_numeric( $key ) || is_string( $key ) ) {
987 +
988 + return SucomDashicons::get( $key );
989 + }
990 +
991 + return self::get_array_or_element( SucomDashicons::get(), $key, $add_none );
992 + }
993 +
994 + /*
995 + * DATE AND TIME METHODS:
996 + *
997 + * format_tz_offset()
998 + * get_default_timezone()
999 + * get_formatted_timezone()
1000 + * get_hours()
1001 + * get_hours_range()
1002 + * get_timezones()
1003 + * get_timezone_abbr()
1004 + * get_timezone_offset_secs()
1005 + * get_timezone_offset_hours()
1006 + * get_tz_name()
1007 + * iso8601_to_seconds()
1008 + * maybe_iso8601_to_seconds()
1009 + * sprintf_date_time()
1010 + */
1011 + public static function format_human_bytes( $bytes, $dec = 2, $sep = ' ' ) {
1012 +
1013 + $size = array( 'B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' );
1014 +
1015 + $factor = floor( ( strlen( $bytes ) - 1 ) / 3 );
1016 +
1017 + return sprintf( "%.{$dec}f{$sep}%s", $bytes / pow( 1024, $factor ), $size[ $factor ] );
1018 + }
1019 +
1020 + /*
1021 + * Returns a date( 'P' ) formatted timezone value (ie. -07:00).
1022 + */
1023 + public static function format_tz_offset( $offset ) {
1024 +
1025 + $hours = (int) $offset;
1026 + $minutes = ( $offset - $hours );
1027 + $sign = ( $offset < 0 ) ? '-' : '+';
1028 + $abs_hour = abs( $hours );
1029 + $abs_mins = abs( $minutes * 60 );
1030 + $tz_offset = sprintf( '%s%02d:%02d', $sign, $abs_hour, $abs_mins );
1031 +
1032 + return $tz_offset;
1033 + }
1034 +
1035 + /*
1036 + * May return a timezone string (ie. 'Africa/Abidjan'), 'UTC', or an offset (ie. '-07:00').
1037 + */
1038 + public static function get_default_timezone() {
1039 +
1040 + static $local_cache = null;
1041 +
1042 + if ( null !== $local_cache ) {
1043 +
1044 + return $local_cache;
1045 + }
1046 +
1047 + if ( function_exists( wp_timezone_string() ) ) {
1048 +
1049 + return $local_cache = wp_timezone_string();
1050 + }
1051 +
1052 + $timezone_string = get_option( 'timezone_string' );
1053 +
1054 + if ( $timezone_string ) {
1055 +
1056 + return $local_cache = $timezone_string;
1057 + }
1058 +
1059 + $offset = (float) get_option( 'gmt_offset' );
1060 +
1061 + $tz_offset = self::format_tz_offset( $offset );
1062 +
1063 + return $local_cache = $tz_offset;
1064 + }
1065 +
1066 + public static function get_formatted_timezone( $tz_name, $format ) {
1067 +
1068 + static $local_cache = array();
1069 +
1070 + if ( isset( $local_cache[ $tz_name ][ $format ] ) ) {
1071 +
1072 + return $local_cache[ $tz_name ][ $format ];
1073 + }
1074 +
1075 + $dt_obj = new DateTime();
1076 +
1077 + $dt_obj->setTimeZone( new DateTimeZone( $tz_name ) );
1078 +
1079 + return $local_cache[ $tz_name ][ $format ] = $dt_obj->format( $format );
1080 + }
1081 +
1082 + public static function get_hours( $step_secs = 3600, $label_format = 'H:i' ) {
1083 +
1084 + return self::get_hours_range( $start_secs = 0, $end_secs = 86400, $step_secs, $label_format );
1085 + }
1086 +
1087 + /*
1088 + * Returns an associative array.
1089 + *
1090 + * Example time formats: 'H:i' (default), 'g:i a'.
1091 + */
1092 + public static function get_hours_range( $start_secs = 0, $end_secs = 86400, $step_secs = 3600, $label_format = 'H:i' ) {
1093 +
1094 + $times = array();
1095 +
1096 + foreach ( range( $start_secs, $end_secs, $step_secs ) as $ts ) {
1097 +
1098 + $value = gmdate( 'H:i', $ts );
1099 +
1100 + if ( 'H:i' !== $label_format ) {
1101 +
1102 + $times[ $value ] = gmdate( $label_format, $ts );
1103 +
1104 + } else $times[ $value ] = $value;
1105 + }
1106 +
1107 + return $times;
1108 + }
1109 +
1110 + /*
1111 + * Returns an associative array of timezone strings (ie. 'Africa/Abidjan'), 'UTC', and offsets (ie. '-07:00').
1112 + */
1113 + public static function get_timezones() {
1114 +
1115 + /*
1116 + * See https://www.php.net/manual/en/function.timezone-identifiers-list.php.
1117 + */
1118 + $timezones = timezone_identifiers_list();
1119 + $timezones = array_combine( $timezones, $timezones ); // Create an associative array.
1120 + $offset_range = array( -12, -11.5, -11, -10.5, -10, -9.5, -9, -8.5, -8, -7.5, -7, -6.5, -6, -5.5, -5, -4.5,
1121 + -4, -3.5, -3, -2.5, -2, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 5.75, 6,
1122 + 6.5, 7, 7.5, 8, 8.5, 8.75, 9, 9.5, 10, 10.5, 11, 11.5, 12, 12.75, 13, 13.75, 14 );
1123 +
1124 + /*
1125 + * Create date( 'P' ) formatted timezone values (ie. -07:00).
1126 + */
1127 + foreach ( $offset_range as $offset ) {
1128 +
1129 + $offset_value = self::format_tz_offset( $offset );
1130 +
1131 + $offset_name = 'UTC' . $offset_value;
1132 +
1133 + $timezones[ $offset_value ] = $offset_name;
1134 + }
1135 +
1136 + return $timezones;
1137 + }
1138 +
1139 + /*
1140 + * Get timezone abbreviation (ie. 'EST', 'MDT', etc.).
1141 + */
1142 + public static function get_timezone_abbr( $tz_name ) {
1143 +
1144 + return self::get_formatted_timezone( $tz_name, 'T' );
1145 + }
1146 +
1147 + /*
1148 + * Get timezone offset in seconds (west of UTC is negative, and east of UTC is positive).
1149 + */
1150 + public static function get_timezone_offset_secs( $tz_name ) {
1151 +
1152 + return self::get_formatted_timezone( $tz_name, 'Z' );
1153 + }
1154 +
1155 + /*
1156 + * Timezone difference to UTC with colon between hours and minutes.
1157 + */
1158 + public static function get_timezone_offset_hours( $tz_name ) {
1159 +
1160 + /*
1161 + * See https://www.php.net/manual/en/datetime.format.php.
1162 + *
1163 + * P Difference to Greenwich time (GMT) with colon between hours and minutes.
1164 + * p The same as P, but returns Z instead of +00:00.
1165 + *
1166 + * Unfortunately 'p' is only available since PHP v8, so we must use 'P' and check for '+00:00'.
1167 + */
1168 + $offset = self::get_formatted_timezone( $tz_name, 'P' );
1169 +
1170 + if ( '+00:00' == $offset ) {
1171 +
1172 + $offset = 'Z';
1173 + }
1174 +
1175 + return $offset;
1176 + }
1177 +
1178 + /*
1179 + * "tz" is used in the method name to hint that the argument is an abbreviation.
1180 + */
1181 + public static function get_tz_name( $tz_abbr ) {
1182 +
1183 + return timezone_name_from_abbr( $tz_abbr );
1184 + }
1185 +
1186 + /*
1187 + * Convert ISO 8601 value (like P2DT15M33S) to seconds.
1188 + */
1189 + public static function iso8601_to_seconds( $iso8601 ) {
1190 +
1191 + $interval = new \DateInterval( $iso8601 );
1192 +
1193 + return ( $interval->d * 24 * 60 * 60 ) + ( $interval->h * 60 * 60 ) + ( $interval->i * 60 ) + $interval->s;
1194 + }
1195 +
1196 + public static function maybe_iso8601_to_seconds( $mixed ) {
1197 +
1198 + if ( 0 === strpos( $mixed, 'P' ) ) {
1199 +
1200 + return self::iso8601_to_seconds( $mixed );
1201 + }
1202 +
1203 + return $mixed;
1204 + }
1205 +
1206 + /*
1207 + * See WpssoUser->add_person_role().
1208 + * See WpssoUser->remove_person_role().
1209 + * See WpssoUtilCache->refresh().
1210 + */
1211 + public static function sprintf_date_time( $fmt = '%1$s %2$s' ) {
1212 +
1213 + $wp_timezone = wp_timezone();
1214 + $wp_date_fmt = get_option( 'date_format' );
1215 + $wp_time_fmt = get_option( 'time_format' );
1216 +
1217 + $now = date_create_immutable( $datetime = 'now', $wp_timezone );
1218 +
1219 + $date_val = $now->format( $wp_date_fmt );
1220 + $time_val = $now->format( $wp_time_fmt );
1221 +
1222 + $date_time_val = sprintf( $fmt, $date_val, $time_val );
1223 +
1224 + return $date_time_val;
1225 + }
1226 +
1227 + /*
1228 + * IS CHECK METHODS:
1229 + *
1230 + * is_assoc()
1231 + * is_https()
1232 + * is_md5()
1233 + * is_non_assoc()
1234 + * is_true()
1235 + * is_valid_option_value()
1236 + *
1237 + * Note that an empty array is not an associative array (ie. returns false for an empty array).
1238 + */
1239 + public static function is_assoc( $mixed ) {
1240 +
1241 + $is_assoc = false;
1242 +
1243 + if ( ! empty( $mixed ) ) { // Optimize.
1244 +
1245 + if ( is_array( $mixed ) ) { // Just in case.
1246 +
1247 + if ( ! is_numeric( implode( array_keys( $mixed ) ) ) ) {
1248 +
1249 + $is_assoc = true;
1250 + }
1251 + }
1252 + }
1253 +
1254 + return $is_assoc;
1255 + }
1256 +
1257 + public static function is_https( $url = '' ) {
1258 +
1259 + static $local_cache = array();
1260 +
1261 + if ( isset( $local_cache[ $url ] ) ) {
1262 +
1263 + return $local_cache[ $url ];
1264 + }
1265 +
1266 + if ( strpos( $url, '://' ) ) {
1267 +
1268 + if ( 'https' === wp_parse_url( $url, PHP_URL_SCHEME ) ) {
1269 +
1270 + return $local_cache[ $url ] = true;
1271 + }
1272 +
1273 + return $local_cache[ $url ] = false;
1274 +
1275 + } elseif ( is_ssl() ) {
1276 +
1277 + return $local_cache[ $url ] = true;
1278 +
1279 + } elseif ( isset( $_SERVER[ 'HTTP_X_FORWARDED_PROTO' ] ) && 'https' === strtolower( $_SERVER[ 'HTTP_X_FORWARDED_PROTO' ] ) ) {
1280 +
1281 + return $local_cache[ $url ] = true;
1282 +
1283 + } elseif ( isset( $_SERVER[ 'HTTP_X_FORWARDED_SSL' ] ) && 'on' === strtolower( $_SERVER[ 'HTTP_X_FORWARDED_SSL' ] ) ) {
1284 +
1285 + return $local_cache[ $url ] = true;
1286 + }
1287 +
1288 + return $local_cache[ $url ] = false;
1289 + }
1290 +
1291 + public static function is_md5( $md5 ) {
1292 +
1293 + return strlen( $md5 ) === 32 && preg_match( '/^[a-f0-9]+$/', $md5 ) ? true : false;
1294 + }
1295 +
1296 + /*
1297 + * Note that an empty array is not an associative array (ie. returns false for an empty array).
1298 + */
1299 + public static function is_non_assoc( $mixed ) {
1300 +
1301 + $is_non_assoc = false;
1302 +
1303 + if ( is_array( $mixed ) ) { // Just in case.
1304 +
1305 + if ( empty( $mixed ) ) { // Optimize.
1306 +
1307 + $is_non_assoc = true;
1308 +
1309 + } elseif ( is_numeric( implode( array_keys( $mixed ) ) ) ) {
1310 +
1311 + $is_non_assoc = true;
1312 + }
1313 + }
1314 +
1315 + return $is_non_assoc;
1316 + }
1317 +
1318 + public static function is_true( $mixed, $allow_null = false ) {
1319 +
1320 + $is_true = is_string( $mixed ) ? filter_var( $mixed, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE ) : (bool) $mixed;
1321 +
1322 + return null === $is_true && ! $allow_null ? false : $is_true;
1323 + }
1324 +
1325 + /*
1326 + * Check that the option value is not true, false, null, empty string, or 'none'.
1327 + */
1328 + public static function is_valid_option_value( $value ) {
1329 +
1330 + if ( true === $value ) {
1331 +
1332 + return false;
1333 +
1334 + } elseif ( empty( $value ) && ! is_numeric( $value ) ) { // False, null, or empty string.
1335 +
1336 + return false;
1337 +
1338 + } elseif ( 'none' === $value ) { // Disabled option.
1339 +
1340 + return false;
1341 + }
1342 +
1343 + return true;
1344 + }
1345 +
1346 + /*
1347 + * OPEN GRAPH AND META TAG METHODS:
1348 + *
1349 + * get_mt_og_seed()
1350 + * get_mt_image_seed()
1351 + * get_mt_product_seed()
1352 + * get_mt_video_seed()
1353 + * get_first_og_image_id()
1354 + * get_first_og_image_url()
1355 + * get_first_og_video_url()
1356 + * get_first_mt_media_id()
1357 + * get_first_mt_media_url()
1358 + * get_publisher_languages()
1359 + * merge_mt_og()
1360 + */
1361 + public static function get_mt_og_seed() {
1362 +
1363 + return array(
1364 + 'fb:admins' => null,
1365 + 'fb:app_id' => null,
1366 + 'og:time' => null, // Internal meta tag.
1367 + 'og:type' => null,
1368 + 'og:url' => null,
1369 + 'og:redirect_url' => null, // Internal meta tag.
1370 + 'og:locale' => null,
1371 + 'og:site_name' => null,
1372 + 'og:title' => null,
1373 + 'og:description' => null,
1374 + 'og:updated_time' => null,
1375 + 'og:video' => null,
1376 + 'og:image' => null,
1377 + 'schema:language' => null, // Internal meta tag.
1378 + 'schema:type:id' => null, // Internal meta tag.
1379 + 'schema:type:url' => null, // Internal meta tag.
1380 + 'schema:type:context' => null, // Internal meta tag.
1381 + 'schema:type:name' => null, // Internal meta tag.
1382 + 'schema:type:path' => null, // Internal meta tag.
1383 + 'schema:review:rating' => null, // Internal meta tag.
1384 + );
1385 + }
1386 +
1387 + /*
1388 + * Pre-define the array key order for the list() construct.
1389 + */
1390 + public static function get_mt_image_seed( $mt_pre = 'og', array $mt_og = array() ) {
1391 +
1392 + $mt_ret = array(
1393 + $mt_pre . ':image:secure_url' => null,
1394 + $mt_pre . ':image:url' => null,
1395 + $mt_pre . ':image:width' => null,
1396 + $mt_pre . ':image:height' => null,
1397 + $mt_pre . ':image:cropped' => null, // Internal meta tag.
1398 + $mt_pre . ':image:id' => null, // Internal meta tag.
1399 + $mt_pre . ':image:alt' => null,
1400 + $mt_pre . ':image:size_name' => null, // Internal meta tag.
1401 + );
1402 +
1403 + return self::merge_mt_og( $mt_ret, $mt_og );
1404 + }
1405 +
1406 + /*
1407 + * This method is used by e-Commerce modules to pre-define and pre-sort the product meta tags.
1408 + *
1409 + * Use null values so WpssoOpengraph->add_data_og_type_md() can load metadata default values.
1410 + */
1411 + public static function get_mt_product_seed( $mt_pre = 'product', array $mt_og = array() ) {
1412 +
1413 + $mt_ret = array(
1414 +
1415 + /*
1416 + * Product part numbers.
1417 + */
1418 + $mt_pre . ':retailer_item_id' => null, // Product ID.
1419 + $mt_pre . ':retailer_part_no' => null, // Product SKU.
1420 + $mt_pre . ':mfr_part_no' => null, // Product MPN.
1421 + $mt_pre . ':item_group_id' => null, // Product variant group ID.
1422 + $mt_pre . ':ean' => null, // aka EAN, EAN-13, GTIN-13.
1423 + $mt_pre . ':gtin14' => null, // Internal meta tag.
1424 + $mt_pre . ':gtin13' => null, // Internal meta tag.
1425 + $mt_pre . ':gtin12' => null, // Internal meta tag.
1426 + $mt_pre . ':gtin8' => null, // Internal meta tag.
1427 + $mt_pre . ':gtin' => null, // Internal meta tag.
1428 + $mt_pre . ':isbn' => null,
1429 + $mt_pre . ':upc' => null, // Aka the UPC, UPC-A, UPC, GTIN-12.
1430 +
1431 + /*
1432 + * Product attributes and descriptions.
1433 + */
1434 + $mt_pre . ':url' => null, // Internal meta tag.
1435 + $mt_pre . ':title' => null, // Internal meta tag.
1436 + $mt_pre . ':description' => null, // Internal meta tag.
1437 + $mt_pre . ':updated_time' => null, // Internal meta tag.
1438 + $mt_pre . ':adult_type' => null, // Internal meta tag.
1439 + $mt_pre . ':age_group' => null,
1440 + $mt_pre . ':quantity' => null, // Internal meta tag.
1441 + $mt_pre . ':availability' => null,
1442 + $mt_pre . ':brand' => null,
1443 + $mt_pre . ':category' => null, // The product category according to the Google product taxonomy.
1444 + $mt_pre . ':retailer_category' => null, // Internal meta tag.
1445 + $mt_pre . ':awards' => array(), // Internal meta tag.
1446 + $mt_pre . ':condition' => null,
1447 + $mt_pre . ':energy_efficiency:value' => null, // Internal meta tag.
1448 + $mt_pre . ':energy_efficiency:min_value' => null, // Internal meta tag.
1449 + $mt_pre . ':energy_efficiency:max_value' => null, // Internal meta tag.
1450 + $mt_pre . ':expiration_time' => null,
1451 + $mt_pre . ':color' => null,
1452 + $mt_pre . ':material' => null,
1453 + $mt_pre . ':mrp_id' => null, // Internal meta tag.
1454 + $mt_pre . ':pattern' => null,
1455 + $mt_pre . ':purchase_limit' => null,
1456 + $mt_pre . ':eligible_quantity:value' => null, // Internal meta tag.
1457 + $mt_pre . ':eligible_quantity:min_value' => null, // Internal meta tag.
1458 + $mt_pre . ':eligible_quantity:max_value' => null, // Internal meta tag.
1459 + $mt_pre . ':eligible_quantity:unit_code' => null, // Internal meta tag.
1460 + $mt_pre . ':eligible_quantity:unit_text' => null, // Internal meta tag.
1461 + $mt_pre . ':target_gender' => null,
1462 + $mt_pre . ':size' => null,
1463 + $mt_pre . ':size_group' => null, // Internal meta tag.
1464 + $mt_pre . ':size_system' => null, // Internal meta tag.
1465 + $mt_pre . ':is_virtual' => null, // Internal meta tag.
1466 +
1467 + /*
1468 + * Product net dimensions and weight.
1469 + */
1470 + $mt_pre . ':length:value' => null, // Internal meta tag.
1471 + $mt_pre . ':length:units' => null, // Internal meta tag (units after value).
1472 + $mt_pre . ':width:value' => null, // Internal meta tag.
1473 + $mt_pre . ':width:units' => null, // Internal meta tag (units after value).
1474 + $mt_pre . ':height:value' => null, // Internal meta tag.
1475 + $mt_pre . ':height:units' => null, // Internal meta tag (units after value).
1476 + $mt_pre . ':weight:value' => null,
1477 + $mt_pre . ':weight:units' => null,
1478 + $mt_pre . ':fluid_volume:value' => null, // Internal meta tag.
1479 + $mt_pre . ':fluid_volume:units' => null, // Internal meta tag (units after value).
1480 +
1481 + /*
1482 + * Product prices.
1483 + */
1484 + $mt_pre . ':min_advert_price:amount' => null, // Internal meta tag.
1485 + $mt_pre . ':min_advert_price:currency' => null, // Internal meta tag.
1486 + $mt_pre . ':original_price:type' => null, // Internal meta tag.
1487 + $mt_pre . ':original_price:amount' => null,
1488 + $mt_pre . ':original_price:currency' => null,
1489 + $mt_pre . ':pretax_price:amount' => null,
1490 + $mt_pre . ':pretax_price:currency' => null,
1491 + $mt_pre . ':price:type' => null, // Internal meta tag.
1492 + $mt_pre . ':price:amount' => null,
1493 + $mt_pre . ':price:currency' => null,
1494 + $mt_pre . ':price:vat_included' => null, // Internal meta tag.
1495 + $mt_pre . ':sale_price:type' => null, // Internal meta tag.
1496 + $mt_pre . ':sale_price:amount' => null,
1497 + $mt_pre . ':sale_price:currency' => null,
1498 + $mt_pre . ':sale_price_dates:start' => null,
1499 + $mt_pre . ':sale_price_dates:start_date' => null, // Internal meta tag.
1500 + $mt_pre . ':sale_price_dates:start_time' => null, // Internal meta tag.
1501 + $mt_pre . ':sale_price_dates:start_timezone' => null, // Internal meta tag.
1502 + $mt_pre . ':sale_price_dates:start_iso' => null, // Internal meta tag.
1503 + $mt_pre . ':sale_price_dates:end' => null,
1504 + $mt_pre . ':sale_price_dates:end_date' => null, // Internal meta tag.
1505 + $mt_pre . ':sale_price_dates:end_time' => null, // Internal meta tag.
1506 + $mt_pre . ':sale_price_dates:end_timezone' => null, // Internal meta tag.
1507 + $mt_pre . ':sale_price_dates:end_iso' => null, // Internal meta tag.
1508 + $mt_pre . ':offers' => array(), // Internal meta tag.
1509 +
1510 + /*
1511 + * Product shipping.
1512 + */
1513 + $mt_pre . ':shipping_cost:amount' => null,
1514 + $mt_pre . ':shipping_cost:currency' => null,
1515 + $mt_pre . ':shipping_length:value' => null, // Internal meta tag.
1516 + $mt_pre . ':shipping_length:units' => null, // Internal meta tag (units after value).
1517 + $mt_pre . ':shipping_width:value' => null, // Internal meta tag.
1518 + $mt_pre . ':shipping_width:units' => null, // Internal meta tag (units after value).
1519 + $mt_pre . ':shipping_height:value' => null, // Internal meta tag.
1520 + $mt_pre . ':shipping_height:units' => null, // Internal meta tag (units after value).
1521 + $mt_pre . ':shipping_weight:value' => null,
1522 + $mt_pre . ':shipping_weight:units' => null,
1523 + $mt_pre . ':shipping_class_id' => null, // Internal meta tag.
1524 + $mt_pre . ':shipping_offers' => array(), // Internal meta tag.
1525 +
1526 + /*
1527 + * Product ratings and reviews.
1528 + */
1529 + $mt_pre . ':rating:average' => null, // Internal meta tag.
1530 + $mt_pre . ':rating:count' => null, // Internal meta tag.
1531 + $mt_pre . ':rating:worst' => null, // Internal meta tag.
1532 + $mt_pre . ':rating:best' => null, // Internal meta tag.
1533 + $mt_pre . ':review:count' => null, // Internal meta tag.
1534 + $mt_pre . ':reviews' => array(), // Internal meta tag.
1535 + );
1536 +
1537 + if ( ! empty( $mt_og[ 'og:type' ] ) && 'product' === $mt_og[ 'og:type' ] ) {
1538 +
1539 + $mt_ret = array_merge( $mt_ret, array(
1540 + $mt_pre . ':variants' => array(), // Internal meta tag.
1541 + ) );
1542 + }
1543 +
1544 + return self::merge_mt_og( $mt_ret, $mt_og );
1545 + }
1546 +
1547 + public static function get_mt_video_seed( $mt_pre = 'og', array $mt_og = array() ) {
1548 +
1549 + $mt_ret = array(
1550 + $mt_pre . ':video:secure_url' => null,
1551 + $mt_pre . ':video:url' => null,
1552 + $mt_pre . ':video:title' => null, // Internal meta tag.
1553 + $mt_pre . ':video:description' => null, // Internal meta tag.
1554 + $mt_pre . ':video:family_friendly' => null, // Internal meta tag.
1555 + $mt_pre . ':video:regions_allowed' => array(), // Internal meta tag.
1556 + $mt_pre . ':video:type' => null, // Example: 'application/x-shockwave-flash', 'text/html', 'video/mp4', etc.
1557 + $mt_pre . ':video:width' => null,
1558 + $mt_pre . ':video:height' => null,
1559 + $mt_pre . ':video:tag' => array(),
1560 + $mt_pre . ':video:duration' => null, // Internal meta tag.
1561 + $mt_pre . ':video:published_date' => null, // Internal meta tag.
1562 + $mt_pre . ':video:upload_date' => null, // Internal meta tag.
1563 + $mt_pre . ':video:thumbnail_url' => null, // Internal meta tag.
1564 + $mt_pre . ':video:embed_url' => null, // Internal meta tag.
1565 + $mt_pre . ':video:stream_url' => null, // Internal meta tag. VideoObject contentUrl.
1566 + $mt_pre . ':video:stream_size' => null, // Internal meta tag. VideoObject contentSize.
1567 + $mt_pre . ':video:has_image' => false, // Internal meta tag.
1568 + $mt_pre . ':video:iphone_name' => null, // Internal meta tag for X (Twitter) player card.
1569 + $mt_pre . ':video:iphone_id' => null, // Internal meta tag for X (Twitter) player card.
1570 + $mt_pre . ':video:iphone_url' => null, // Internal meta tag for X (Twitter) player card.
1571 + $mt_pre . ':video:ipad_name' => null, // Internal meta tag for X (Twitter) player card.
1572 + $mt_pre . ':video:ipad_id' => null, // Internal meta tag for X (Twitter) player card.
1573 + $mt_pre . ':video:ipad_url' => null, // Internal meta tag for X (Twitter) player card.
1574 + $mt_pre . ':video:googleplay_name' => null, // Internal meta tag for X (Twitter) player card.
1575 + $mt_pre . ':video:googleplay_id' => null, // Internal meta tag for X (Twitter) player card.
1576 + $mt_pre . ':video:googleplay_url' => null, // Internal meta tag for X (Twitter) player card.
1577 + );
1578 +
1579 + $mt_ret += self::get_mt_image_seed( $mt_pre );
1580 +
1581 + /*
1582 + * Facebook applink meta tags.
1583 + */
1584 + if ( $mt_pre === 'og' ) {
1585 +
1586 + $mt_ret += array(
1587 + 'al:ios:app_name' => null,
1588 + 'al:ios:app_store_id' => null,
1589 + 'al:ios:url' => null,
1590 + 'al:android:app_name' => null,
1591 + 'al:android:package' => null,
1592 + 'al:android:url' => null,
1593 + 'al:web:url' => null,
1594 + 'al:web:should_fallback' => 'false',
1595 + );
1596 + }
1597 +
1598 + return self::merge_mt_og( $mt_ret, $mt_og );
1599 + }
1600 +
1601 + public static function get_first_og_image_id( array $assoc ) {
1602 +
1603 + return self::get_first_mt_media_id( $assoc, $media_pre = 'og:image' );
1604 + }
1605 +
1606 + public static function get_first_og_image_url( array $assoc ) {
1607 +
1608 + return self::get_first_mt_media_url( $assoc, $media_pre = 'og:image', $mt_suffixes = array( ':secure_url', ':url', '' ) );
1609 + }
1610 +
1611 + public static function get_first_og_video_url( array $assoc ) {
1612 +
1613 + return self::get_first_mt_media_url( $assoc, $media_pre = 'og:video' );
1614 + }
1615 +
1616 + public static function get_first_mt_media_id( array $assoc, $media_pre = 'og:image' ) {
1617 +
1618 + return self::get_first_mt_media_url( $assoc, $media_pre, $mt_suffixes = array( ':id' ) );
1619 + }
1620 +
1621 + /*
1622 + * Return the first URL from the associative array (og:image:secure_url, og:image:url, og:image).
1623 + */
1624 + public static function get_first_mt_media_url( array $assoc, $media_pre = 'og:image', $mt_suffixes = null ) {
1625 +
1626 + /*
1627 + * Check for two dimensional arrays and keep following the first array element.
1628 + *
1629 + * Prefer the $media_pre array key (if it's available).
1630 + */
1631 + if ( isset( $assoc[ $media_pre ] ) && is_array( $assoc[ $media_pre ] ) ) {
1632 +
1633 + $first_el = reset( $assoc[ $media_pre ] );
1634 +
1635 + } else $first_el = reset( $assoc ); // Can be array or string.
1636 +
1637 + /*
1638 + * If the first element isn't a string (ie. non-array value), then recurse until we hit bottom.
1639 + */
1640 + if ( is_array( $first_el ) ) {
1641 +
1642 + return self::get_first_mt_media_url( $first_el, $media_pre, $mt_suffixes );
1643 + }
1644 +
1645 + if ( ! is_array( $mt_suffixes ) ) { // Array of meta tag suffixes to use.
1646 +
1647 + $mt_suffixes = array( ':secure_url', ':url', '', ':embed_url', ':stream_url' );
1648 + }
1649 +
1650 + /*
1651 + * First element is a text string, so check the array keys.
1652 + */
1653 + foreach ( $mt_suffixes as $mt_suffix ) {
1654 +
1655 + if ( ! empty( $assoc[ $media_pre . $mt_suffix ] ) ) {
1656 +
1657 + return $assoc[ $media_pre . $mt_suffix ]; // Return first match.
1658 + }
1659 + }
1660 +
1661 + return ''; // Empty string.
1662 + }
1663 +
1664 + public static function get_publisher_languages( $publisher = '' ) {
1665 +
1666 + switch ( $publisher ) {
1667 +
1668 + case 'facebook':
1669 + case 'fb':
1670 +
1671 + return self::$publisher_languages[ 'facebook' ];
1672 +
1673 + case 'google':
1674 +
1675 + return self::$publisher_languages[ 'google' ];
1676 +
1677 + case 'pinterest':
1678 + case 'pin':
1679 + case 'rp':
1680 +
1681 + return self::$publisher_languages[ 'pinterest' ];
1682 +
1683 + default:
1684 +
1685 + if ( isset( self::$publisher_languages[ $publisher ] ) ) {
1686 +
1687 + return self::$publisher_languages[ $publisher ];
1688 + }
1689 +
1690 + return array();
1691 + }
1692 + }
1693 +
1694 + /*
1695 + * Protected method used by get_mt_image_seed(), get_mt_product_seed(), and get_mt_video_seed().
1696 + */
1697 + protected static function merge_mt_og( array $mt_ret, array $mt_og ) {
1698 +
1699 + if ( empty( $mt_og ) ) { // Nothing to merge.
1700 +
1701 + return $mt_ret;
1702 + }
1703 +
1704 + /*
1705 + * Always keep the 'og:type' meta tag top-most.
1706 + *
1707 + * Use array_key_exists() to allow for null value.
1708 + */
1709 + if ( array_key_exists( 'og:type', $mt_og ) ) {
1710 +
1711 + return array_merge( array( 'og:type' => $mt_og[ 'og:type' ] ), $mt_ret, $mt_og );
1712 + }
1713 +
1714 + return array_merge( $mt_ret, $mt_og );
1715 + }
1716 +
1717 + /*
1718 + * SANITATION METHODS:
1719 + *
1720 + * sanitize_classname()
1721 + * sanitize_css_class()
1722 + * sanitize_css_id()
1723 + * sanitize_file_name()
1724 + * sanitize_file_path()
1725 + * sanitize_hashtags()
1726 + * sanitize_hookname()
1727 + * sanitize_input_name()
1728 + * sanitize_int()
1729 + * sanitize_key()
1730 + * sanitize_locale()
1731 + * sanitize_meta_key()
1732 + * sanitize_tag()
1733 + * sanitize_twitter_name()
1734 + * sanitize_use_post()
1735 + *
1736 + * Used by WpssoConfig::load_lib() to sanitize file names to class names.
1737 + *
1738 + * See https://www.php.net/manual/en/language.variables.basics.php.
1739 + */
1740 + public static function sanitize_classname( $classname, $allow_underscore = true ) {
1741 +
1742 + $classname = preg_replace( '/^[^a-zA-Z_\x80-\xff]+/', '', $classname ); # Cannot start with numeric characters.
1743 + $classname = preg_replace( '/[^a-zA-Z0-9_\x80-\xff]/', '', $classname );
1744 +
1745 + if ( ! $allow_underscore ) $classname = preg_replace( '/_/', '', $classname ); # Remove underscores.
1746 +
1747 + return $classname;
1748 + }
1749 +
1750 + public static function sanitize_css_class( $css_class, $sep = '-' ) {
1751 +
1752 + $css_class = preg_replace( '/[^a-zA-Z0-9_\- ]+/', $sep, $css_class ); // Spaces allowed.
1753 + $css_class = trim( $css_class, $sep . ' ' ); // Trim separator and space characters.
1754 +
1755 + return $css_class;
1756 + }
1757 +
1758 + /*
1759 + * See sucomChangeHideUnhideRows() in jquery-metabox.js.
1760 + * See sucomSanitizeCssId() in jquery-admin-page.js.
1761 + */
1762 + public static function sanitize_css_id( $css_id, $sep = '-' ) {
1763 +
1764 + $css_id = preg_replace( '/[^a-zA-Z0-9_\-]+/', $sep, $css_id ); // Spaces not allowed.
1765 + $css_id = trim( $css_id, $sep );
1766 +
1767 + return $css_id;
1768 + }
1769 +
1770 + public static function sanitize_file_name( $file_name ) {
1771 +
1772 + if ( '' === $file_name ) { // Just in case.
1773 +
1774 + return $file_name;
1775 + }
1776 +
1777 + $special_chars = array( '?', '[', ']', '/', '\\', '=', '<', '>', ':', ';', ',', '\'', '"',
1778 + '&', '$', '#', '*', '(', ')', '|', '~', '`', '!', '{', '}', '%', '+', chr( 0 ) );
1779 +
1780 + $file_name = preg_replace( '#\x{00a0}#siu', ' ', $file_name );
1781 + $file_name = str_replace( $special_chars, '', $file_name );
1782 + $file_name = str_replace( array( '%20', '+' ), '-', $file_name );
1783 + $file_name = preg_replace( '/[\r\n\t -]+/', '-', $file_name );
1784 + $file_name = trim( $file_name, '.-_' );
1785 +
1786 + return $file_name;
1787 + }
1788 +
1789 + public static function sanitize_file_path( $file_path ) {
1790 +
1791 + if ( empty( $file_path ) ) { // Just in case.
1792 +
1793 + return false;
1794 + }
1795 +
1796 + $file_path = implode( $glue = '/', array_map( array( __CLASS__, 'sanitize_file_name' ), explode( '/', $file_path ) ) );
1797 +
1798 + return $file_path;
1799 + }
1800 +
1801 + /*
1802 + * Note that hashtags cannot begin with a number. This method truncates tags that begin with a number.
1803 + */
1804 + public static function sanitize_hashtags( array $tags = array() ) {
1805 +
1806 + return preg_replace( array( '/^[0-9].*/', '/[ \[\]#!\$\?\\\\\/\*\+\.\-\^]/', '/^.+/' ), array( '', '', '#$0' ), $tags );
1807 + }
1808 +
1809 + /*
1810 + * See sucomSanitizeHookname() in jquery-admin-page.js.
1811 + */
1812 + public static function sanitize_hookname( $hookname ) {
1813 +
1814 + $hookname = preg_replace( '/[\/\-\. \[\]:#]+/', '_', $hookname );
1815 + $hookname = rtrim( $hookname, '_' ); // Only trim right side underscores to allow for '__return_false'.
1816 +
1817 + return self::sanitize_key( $hookname, $allow_upper = false );
1818 + }
1819 +
1820 + /*
1821 + * See WpssoConfig::$cf[ 'opt' ][ 'defaults' ] for example input names.
1822 + *
1823 + * A colon can be used for qualifiers (example, ':disabled', ':width', ':height', etc.).
1824 + *
1825 + * A hashtag can be used for the locale (language).
1826 + *
1827 + * Example sanitation:
1828 + *
1829 + * 'mrp_method_https://schema.org/ReturnByMail' -> 'mrp_method_https_schema_org_ReturnByMail'
1830 + */
1831 + public static function sanitize_input_name( $input_name, $sep = '_' ) {
1832 +
1833 + $input_name = preg_replace( '/:\/\//', $sep, $input_name );
1834 + $input_name = preg_replace( '/[^a-zA-Z0-9_\-:#]+/', $sep, $input_name );
1835 + $input_name = trim( $input_name, $sep );
1836 +
1837 + return $input_name;
1838 + }
1839 +
1840 + /*
1841 + * There is no WordPress function to sanitize post IDs and integers.
1842 + *
1843 + * Returns an integer or null.
1844 + */
1845 + public static function sanitize_int( $value ) {
1846 +
1847 + if ( is_numeric( $value ) ) {
1848 +
1849 + return (int) $value;
1850 + }
1851 +
1852 + return null;
1853 + }
1854 +
1855 + /*
1856 + * Sanitize an option array key.
1857 + *
1858 + * Unlike the WordPress sanitize_key() function, this method allows for colon and hash characters and (optionally)
1859 + * upper case characters.
1860 + *
1861 + * See sucomSanitizeKey() in wpsso/js/com/jquery-admin-page.js
1862 + * See wordpress/wp-includes/formatting.php.
1863 + */
1864 + public static function sanitize_key( $key, $allow_upper = false ) {
1865 +
1866 + if ( is_scalar( $key ) ) { // Int, float, string or bool.
1867 +
1868 + if ( ! $allow_upper ) $key = strtolower( $key ); // Convert upper case characters to lower case.
1869 +
1870 + return preg_replace( '/[^a-zA-Z0-9_\-:#]/', '', $key );
1871 + }
1872 +
1873 + return '';
1874 + }
1875 +
1876 + public static function sanitize_schema_id( $key ) {
1877 +
1878 + if ( is_scalar( $key ) ) { // Int, float, string or bool.
1879 +
1880 + $key = strtolower( $key ); // Convert upper case characters to lower case.
1881 + $key = preg_replace( '/[_\-]/', '.', $key ); // Convert underscores and hyphens to periods.
1882 + $key = preg_replace( '/[^a-z\.]/', '', $key ); // Keep only alphabetic and period characters.
1883 +
1884 + } else $key = '';
1885 +
1886 + return $key;
1887 + }
1888 +
1889 + public static function sanitize_locale( $locale ) {
1890 +
1891 + $locale = str_replace( '-', '_', $locale ); // Convert 'en-US' to 'en_US'.
1892 + $locale = preg_replace( '/[^a-zA-Z_]/', '', $locale );
1893 +
1894 + return $locale;
1895 + }
1896 +
1897 + /*
1898 + * Decode and remove html/js/css and quotes.
1899 + */
1900 + public static function sanitize_meta_key( $meta_key ) {
1901 +
1902 + $meta_key = self::decode_html( $meta_key );
1903 + $meta_key = self::strip_html( $meta_key );
1904 + $meta_key = preg_replace( '/[\'\"]/', '', $meta_key );
1905 +
1906 + return $meta_key;
1907 + }
1908 +
1909 + public static function sanitize_tag( $tag ) {
1910 +
1911 + $tag = sanitize_title_with_dashes( $tag, '', 'display' );
1912 + $tag = urldecode( $tag );
1913 +
1914 + return $tag;
1915 + }
1916 +
1917 + public static function sanitize_twitter_name( $twitter_name, $prefix_at = true ) {
1918 +
1919 + if ( '' !== $twitter_name ) {
1920 +
1921 + $twitter_name = substr( preg_replace( array( '/^.*\//', '/[^a-zA-Z0-9_]/' ), '', $twitter_name ), 0, 15 );
1922 +
1923 + if ( ! empty( $twitter_name ) && $prefix_at ) {
1924 +
1925 + $twitter_name = '@' . $twitter_name;
1926 + }
1927 + }
1928 +
1929 + return $twitter_name;
1930 + }
1931 +
1932 + /*
1933 + * Note that an empty string or a null is sanitized as false.
1934 + *
1935 + * Used by the wpssorrssb_get_sharing_buttons() function and the WpssoRrssbShortcodeSharing->do_shortcode() method.
1936 + */
1937 + public static function sanitize_use_post( $mixed, $default = true ) {
1938 +
1939 + if ( is_array( $mixed ) ) {
1940 +
1941 + $use_post = isset( $mixed[ 'use_post' ] ) ? $mixed[ 'use_post' ] : $default;
1942 +
1943 + } elseif ( is_object( $mixed ) ) {
1944 +
1945 + $use_post = isset( $mixed->use_post ) ? $mixed->use_post : $default;
1946 +
1947 + } else $use_post = $mixed;
1948 +
1949 + if ( empty( $use_post ) || 'false' === $use_post ) { // 0, false, or 'false'
1950 +
1951 + return false;
1952 +
1953 + } elseif ( is_numeric( $use_post ) ) {
1954 +
1955 + return (int) $use_post;
1956 + }
1957 +
1958 + return $default;
1959 + }
1960 +
1961 + /*
1962 + * TEXT HANDLING METHODS:
1963 + *
1964 + * append_url_fragment()
1965 + * decode_html()
1966 + * decode_utf8()
1967 + * encode_html_emoji()
1968 + * decode_url_add_query()
1969 + * encode_utf8()
1970 + * esc_url_encode()
1971 + * explode_csv()
1972 + * get_bool()
1973 + * get_bool_string()
1974 + * get_const()
1975 + * get_file_path_locale()
1976 + * get_json_scripts()
1977 + * get_mod_css_id()
1978 + * get_mod_salt()
1979 + * get_prot()
1980 + * get_stripped_php()
1981 + * get_request_value()
1982 + * get_url()
1983 + * get_use_post_string()
1984 + * insert_html_tag_attributes()
1985 + * mb_convert_encoding_ucs2_utf8()
1986 + * mb_decode_numericentity_utf8()
1987 + * minify_css()
1988 + * replace_unicode_escape()
1989 + * restore_checkboxes()
1990 + * safe_error_log()
1991 + * strip_html()
1992 + * strip_shortcodes()
1993 + * strnatcasecmp_remove_accents()
1994 + * unparse_url()
1995 + * unquote_csv_value()
1996 + * update_prot()
1997 + *
1998 + * Add a fragment to a URL.
1999 + */
2000 + public static function append_url_fragment( $url, $fragment ) {
2001 +
2002 + return preg_replace( '/#.*/', '', $url ) . ( empty( $fragment ) ? '' : '#' . self::sanitize_css_id( $fragment ) );
2003 + }
2004 +
2005 + /*
2006 + * Decode HTML entities and UTF8 encoding.
2007 + */
2008 + public static function decode_html( $encoded ) {
2009 +
2010 + if ( false === strpos( $encoded, '&' ) ) {
2011 +
2012 + return $encoded;
2013 + }
2014 +
2015 + static $charset = null;
2016 +
2017 + if ( null === $charset ) {
2018 +
2019 + if ( function_exists( 'get_bloginfo' ) ) {
2020 +
2021 + $charset = get_bloginfo( $show = 'charset', $filter = 'raw' );
2022 + }
2023 + }
2024 +
2025 + return html_entity_decode( self::decode_utf8( $encoded ), ENT_QUOTES, $charset );
2026 + }
2027 +
2028 + public static function decode_url_add_query( $url, array $args ) {
2029 +
2030 + if ( false === filter_var( $url, FILTER_VALIDATE_URL ) ) { // Invalid URL.
2031 +
2032 + return false;
2033 + }
2034 +
2035 + $parsed_url = wp_parse_url( self::decode_html( urldecode( $url ) ) );
2036 +
2037 + if ( empty( $parsed_url ) ) {
2038 +
2039 + return false;
2040 + }
2041 +
2042 + if ( empty( $parsed_url[ 'query' ] ) ) {
2043 +
2044 + $parsed_url[ 'query' ] = http_build_query( $args );
2045 +
2046 + } else $parsed_url[ 'query' ] .= '&' . http_build_query( $args );
2047 +
2048 + $url = self::unparse_url( $parsed_url );
2049 +
2050 + return $url;
2051 + }
2052 +
2053 + public static function decode_utf8( $encoded ) {
2054 +
2055 + if ( false === strpos( $encoded, '&#' ) ) {
2056 +
2057 + return $encoded;
2058 + }
2059 +
2060 + $encoded = preg_replace( '/&#8230;/', '...', $encoded );
2061 +
2062 + if ( function_exists( 'mb_decode_numericentity' ) ) { // Just in case.
2063 +
2064 + return preg_replace_callback( '/&#\d{2,5};/u', array( __CLASS__, 'mb_decode_numericentity_utf8' ), $encoded );
2065 + }
2066 +
2067 + return $encoded;
2068 + }
2069 +
2070 + public static function encode_html_emoji( $content ) {
2071 +
2072 + static $charset = null;
2073 +
2074 + if ( null === $charset ) {
2075 +
2076 + if ( function_exists( 'get_bloginfo' ) ) {
2077 +
2078 + $charset = get_bloginfo( $show = 'charset', $filter = 'raw' );
2079 + }
2080 + }
2081 +
2082 + $content = htmlentities( $content, ENT_QUOTES, $charset, $double_encode = false );
2083 +
2084 + if ( function_exists( 'wp_encode_emoji' ) ) {
2085 +
2086 + $content = wp_encode_emoji( $content );
2087 + }
2088 +
2089 + return $content;
2090 + }
2091 +
2092 + public static function encode_utf8( $decoded ) {
2093 +
2094 + $encoded = $decoded;
2095 +
2096 + if ( function_exists( 'mb_detect_encoding' ) ) { // Just in case.
2097 +
2098 + if ( mb_detect_encoding( $decoded, 'UTF-8') !== 'UTF-8' ) {
2099 +
2100 + if ( function_exists( 'utf8_encode' ) ) {
2101 +
2102 + $encoded = utf8_encode( $decoded );
2103 + }
2104 + }
2105 + }
2106 +
2107 + return $encoded;
2108 + }
2109 +
2110 + public static function esc_url_encode( $url, $esc_url = true ) {
2111 +
2112 + $decoded_url = self::decode_html( $url ); // Decode HTML entities.
2113 + $encoded_url = urlencode( $esc_url ? esc_url_raw( $decoded_url ) : $decoded_url );
2114 + $replace = array( '%21', '%2A', '%27', '%28', '%29', '%3B', '%3A', '%40', '%26', '%3D', '%2B', '%24', '%2C', '%2F',
2115 + '%3F', '%25', '%23', '%5B', '%5D' );
2116 + $allowed = array( '!', '*', '\'', '(', ')', ';', ':', '@', '&', '=', '+', '$', ',', '/', '?', '%', '#', '[', ']' );
2117 +
2118 + return str_replace( $replace, $allowed, $encoded_url );
2119 + }
2120 +
2121 + public static function explode_csv( $str ) {
2122 +
2123 + if ( empty( $str ) ) {
2124 +
2125 + return array();
2126 + }
2127 +
2128 + return array_map( array( __CLASS__, 'unquote_csv_value' ), explode( ',', $str ) );
2129 + }
2130 +
2131 + /*
2132 + * Maybe convert string to boolean.
2133 + *
2134 + * See WpssoFaqShortcodeQuestion->do_shortcode().
2135 + */
2136 + public static function get_bool( $mixed ) {
2137 +
2138 + return is_string( $mixed ) ? filter_var( $mixed, FILTER_VALIDATE_BOOLEAN ) : (bool) $mixed;
2139 + }
2140 +
2141 + public static function get_bool_string( $mixed ) {
2142 +
2143 + if ( false === $mixed ) {
2144 +
2145 + return 'false';
2146 +
2147 + } elseif ( true === $mixed ) {
2148 +
2149 + return 'true';
2150 +
2151 + } elseif ( null === $mixed ) {
2152 +
2153 + return 'null';
2154 + }
2155 +
2156 + return (string) $mixed;
2157 + }
2158 +
2159 + /*
2160 + * Return a constant value, or $undef if not defined.
2161 + */
2162 + public static function get_const( $const, $undef = null ) {
2163 +
2164 + return defined( $const ) ? constant( $const ) : $undef;
2165 + }
2166 +
2167 + /*
2168 + * Check for a localized file name.
2169 + */
2170 + public static function get_file_path_locale( $file_path ) {
2171 +
2172 + if ( ! class_exists( 'SucomUtilWP' ) ) { // Just in case.
2173 +
2174 + require_once dirname( __FILE__ ) . '/util-wp.php';
2175 + }
2176 +
2177 + if ( preg_match( '/^(.*)(\.[a-z0-9]+)$/', $file_path, $matches ) ) {
2178 +
2179 + if ( ! empty( $matches[ 2 ] ) ) { // Just in case.
2180 +
2181 + $file_path_locale = $matches[ 1 ] . '-' . SucomUtilWP::get_locale() . $matches[ 2 ];
2182 +
2183 + if ( file_exists( $file_path_locale ) ) {
2184 +
2185 + $file_path = $file_path_locale;
2186 + }
2187 + }
2188 + }
2189 +
2190 + return $file_path;
2191 + }
2192 +
2193 + public static function get_json_scripts( $html, $do_decode = true ) {
2194 +
2195 + /*
2196 + * Remove containers that should not include json scripts.
2197 + *
2198 + * i = Letters in the pattern match both upper and lower case letters.
2199 + * m = The "^" and "$" constructs match newlines and the complete subject string.
2200 + * s = A dot metacharacter in the pattern matches all characters, including newlines.
2201 + * U = Invert greediness of quantifiers, so they are NOT greedy by default, but become greedy if followed by ?.
2202 + *
2203 + * See http://php.net/manual/en/reference.pcre.pattern.modifiers.php.
2204 + */
2205 + $html = preg_replace( '/<!--.*-->/Ums', '', $html );
2206 + $html = preg_replace( '/<pre[ >].*<\/pre>/Uims', '', $html );
2207 + $html = preg_replace( '/<textarea[ >].*<\/textarea>/Uims', '', $html );
2208 +
2209 + $json_scripts = array();
2210 +
2211 + /*
2212 + * i = Letters in the pattern match both upper and lower case letters.
2213 + * s = A dot metacharacter in the pattern matches all characters, including newlines.
2214 + * U = Inverts the "greediness" of quantifiers so that they are not greedy by default.
2215 + *
2216 + * See http://php.net/manual/en/reference.pcre.pattern.modifiers.php.
2217 + */
2218 + if ( preg_match_all( '/(<script\b[^>]*type=["\']application\/ld\+json["\'][^>]*>)(.+)(<\/script>)/Uis', $html, $all_matches, PREG_SET_ORDER ) ) {
2219 +
2220 + foreach ( $all_matches as $num => $matches ) {
2221 +
2222 + $json_data = json_decode( $matches[ 2 ], $assoc = true );
2223 +
2224 + if ( preg_match( '/ id=["\']([^"\']+)["\']/', $matches[ 1 ], $m ) ) {
2225 +
2226 + $single_id = 'id:' . $m[ 1 ];
2227 +
2228 + } else $single_id = 'md5:' . md5( serialize( $json_data ) ); // md5() input must be a string.
2229 +
2230 + if ( $do_decode ) { // Return the decoded json data.
2231 +
2232 + if ( is_array( $json_data ) ) {
2233 +
2234 + $json_scripts[ $single_id ] = $json_data;
2235 +
2236 + } else {
2237 +
2238 + $error_pre = sprintf( '%s error:', __METHOD__ );
2239 +
2240 + $error_msg = sprintf( 'Error decoding json script: %s', print_r( $matches[ 2 ], true ) );
2241 +
2242 + self::safe_error_log( $error_pre . ' ' . $error_msg );
2243 + }
2244 +
2245 + } else { // Return the json script instead.
2246 +
2247 + $json_scripts[ $single_id ] = $matches[ 0 ];
2248 + }
2249 + }
2250 + }
2251 +
2252 + return $json_scripts;
2253 + }
2254 +
2255 + public static function get_mod_css_id( array $mod, $sep = '-' ) {
2256 +
2257 + /*
2258 + * Note that the sort order, page number, locale, amp and embed checks are provided by
2259 + * WpssoHead->get_head_cache_index() and not SucomUtil::get_mod_salt().
2260 + *
2261 + * Example cache salts:
2262 + *
2263 + * 'post:123_type:page'
2264 + * 'post:123_type:product_is_pta' // WooCommerce shop page.
2265 + * 'term:123_tax:product_cat' // WooCommerce category page.
2266 + */
2267 + $css_id = self::get_mod_salt( $mod, $canonical_url = false, $sep );
2268 + $css_id = self::sanitize_css_id( $css_id );
2269 +
2270 + return $css_id;
2271 + }
2272 +
2273 + /*
2274 + * A cache salt string based on the $mod array. If $mod is not an array, then use the canonical URL value.
2275 + *
2276 + * Note that the sort order, page number, locale, amp and embed checks are provided by
2277 + * WpssoHead->get_head_cache_index() and not SucomUtil::get_mod_salt().
2278 + *
2279 + * Example cache salts:
2280 + *
2281 + * 'post:123_type:page'
2282 + * 'post:123_type:product_is_pta' // WooCommerce shop page.
2283 + * 'term:123_tax:product_cat' // WooCommerce category page.
2284 + *
2285 + * 'is_home_url:https_example_com' // When a canonical URL is provided.
2286 + * 'post:123_type:page_url:https_example_com_page-slug' // When a canonical URL is provided.
2287 + * 'url:https_example_com_2022_01' // When a canonical URL is provided.
2288 + */
2289 + public static function get_mod_salt( $mod = false, $canonical_url = false, $sep = '_' ) {
2290 +
2291 + $mod_salt = '';
2292 +
2293 + if ( is_array( $mod ) ) {
2294 +
2295 + if ( ! empty( $mod[ 'name' ] ) ) { // Add the module name and ID.
2296 +
2297 + $mod_salt .= $sep . $mod[ 'name' ];
2298 +
2299 + if ( is_bool( $mod[ 'id' ] ) ) {
2300 +
2301 + $mod_salt .= ':' . ( $mod[ 'id' ] ? 'true' : 'false' );
2302 +
2303 + } elseif ( is_numeric( $mod[ 'id' ] ) ) { // Just in case.
2304 +
2305 + $mod_salt .= ':' . $mod[ 'id' ];
2306 + }
2307 + }
2308 +
2309 + if ( ! empty( $mod[ 'post_type' ] ) ) { // Add the post type name.
2310 +
2311 + $mod_salt .= $sep . 'type:' . ( is_string( $mod[ 'post_type' ] ) ?
2312 + $mod[ 'post_type' ] : print_r( $mod[ 'post_type' ], true ) );
2313 +
2314 + if ( ! empty( $mod[ 'is_post_type_archive' ] ) ) { // Post type archive page.
2315 +
2316 + $mod_salt .= $sep . 'is_pta';
2317 + }
2318 +
2319 + } elseif ( ! empty( $mod[ 'tax_slug' ] ) ) { // Add the taxonomy name.
2320 +
2321 + $mod_salt .= $sep . 'tax:' . $mod[ 'tax_slug' ];
2322 + }
2323 +
2324 + if ( ! empty( $mod[ 'is_home' ] ) ) { // Home page (static or blog archive).
2325 +
2326 + $mod_salt .= $sep . 'is_home';
2327 + }
2328 + }
2329 +
2330 + if ( ! empty( $canonical_url ) ) {
2331 +
2332 + $mod_salt .= $sep . 'url:' . self::sanitize_input_name( $canonical_url, $sep );
2333 + }
2334 +
2335 + $mod_salt = trim( $mod_salt, $sep );
2336 +
2337 + return apply_filters( 'sucom_mod_salt', $mod_salt, $canonical_url );
2338 + }
2339 +
2340 + public static function get_prot( $url = '' ) {
2341 +
2342 + if ( $url ) {
2343 +
2344 + return self::is_https( $url ) ? 'https' : 'http';
2345 +
2346 + } elseif ( self::is_https() ) {
2347 +
2348 + return 'https';
2349 +
2350 + } elseif ( is_admin() ) {
2351 +
2352 + if ( defined( 'FORCE_SSL_ADMIN' ) && FORCE_SSL_ADMIN ) {
2353 +
2354 + return 'https';
2355 + }
2356 +
2357 + } elseif ( defined( 'FORCE_SSL' ) && FORCE_SSL ) {
2358 +
2359 + return 'https';
2360 + }
2361 +
2362 + return 'http';
2363 + }
2364 +
2365 + /*
2366 + * $method = 'ANY' uses the current request method.
2367 + */
2368 + public static function get_request_value( $key, $method = 'ANY', $default = '' ) {
2369 +
2370 + switch ( 'ANY' === $method ? $_SERVER[ 'REQUEST_METHOD' ] : $method ) {
2371 +
2372 + case 'POST':
2373 +
2374 + if ( isset( $_POST[ $key ] ) ) {
2375 +
2376 + return sanitize_text_field( $_POST[ $key ] );
2377 + }
2378 +
2379 + break;
2380 +
2381 + case 'GET':
2382 +
2383 + if ( isset( $_GET[ $key ] ) ) {
2384 +
2385 + return sanitize_text_field( $_GET[ $key ] );
2386 + }
2387 +
2388 + break;
2389 + }
2390 +
2391 + return $default;
2392 + }
2393 +
2394 + public static function get_stripped_php( $file_path ) {
2395 +
2396 + $stripped_php = '';
2397 +
2398 + if ( file_exists( $file_path ) ) {
2399 +
2400 + $content = file_get_contents( $file_path );
2401 +
2402 + $comments = array( T_COMMENT );
2403 +
2404 + if ( defined( 'T_DOC_COMMENT' ) ) {
2405 +
2406 + $comments[] = T_DOC_COMMENT; // PHP 5.
2407 + }
2408 +
2409 + if ( defined( 'T_ML_COMMENT' ) ) {
2410 +
2411 + $comments[] = T_ML_COMMENT; // PHP 4.
2412 + }
2413 +
2414 + $tokens = token_get_all( $content );
2415 +
2416 + foreach ( $tokens as $token ) {
2417 +
2418 + if ( is_array( $token ) ) {
2419 +
2420 + if ( in_array( $token[ 0 ], $comments ) ) {
2421 +
2422 + continue;
2423 + }
2424 +
2425 + $token = $token[ 1 ];
2426 + }
2427 +
2428 + $stripped_php .= $token;
2429 + }
2430 +
2431 + } else $stripped_php = false;
2432 +
2433 + return $stripped_php;
2434 + }
2435 +
2436 + /*
2437 + * Get the current $_SERVER[ 'REQUEST_URI' ] URL, optionally with tracking and advertising query args removed.
2438 + */
2439 + public static function get_url( $clean_args = true ) {
2440 +
2441 + static $local_cache = array();
2442 +
2443 + $cache_idx = $clean_args ? 0 : 1; // Converts null to 0.
2444 +
2445 + if ( isset( $local_cache[ $cache_idx ] ) ) {
2446 +
2447 + return $local_cache[ $cache_idx ];
2448 + }
2449 +
2450 + $base_url = preg_replace( '/^(.*\/\/[^\/]*).*$/', '$1', get_home_url() );
2451 +
2452 + $local_cache[ $cache_idx ] = esc_url_raw( $base_url . $_SERVER[ 'REQUEST_URI' ] );
2453 +
2454 + if ( $clean_args ) { // Remove tracking and advertising query args.
2455 +
2456 + $query_args = apply_filters( 'sucom_url_clean_query_args', self::$url_clean_query );
2457 +
2458 + if ( ! empty( $query_args ) ) { // Just in case.
2459 +
2460 + $query_args = array_flip( $query_args ); // Move values to keys.
2461 +
2462 + $query_args = array_fill_keys( array_keys( $query_args ), false ); // Set all values to false.
2463 +
2464 + $local_cache[ $cache_idx ] = add_query_arg( $query_args, $local_cache[ $cache_idx ] ); // Remove keys with false values.
2465 + }
2466 + }
2467 +
2468 + return $local_cache[ $cache_idx ];
2469 + }
2470 +
2471 + public static function get_use_post_string( $use_post ) {
2472 +
2473 + $use_post = self::sanitize_use_post( $use_post );
2474 +
2475 + return self::get_bool_string( $use_post );
2476 + }
2477 +
2478 + /*
2479 + * Add one or more attributes to the HTML tag.
2480 + *
2481 + * Example HTML tag:
2482 + *
2483 + * $html argument = '<img src="/image.jpg">
2484 + * $html returned = '<img src="/image.jpg" data-pin-nopin="nopin">'
2485 + */
2486 + public static function insert_html_tag_attributes( $html, array $attr_names_values ) {
2487 +
2488 + foreach ( $attr_names_values as $attr_name => $attr_value ) {
2489 +
2490 + if ( false !== $attr_value && false === strpos( $html, ' ' . $attr_name . '=' ) ) {
2491 +
2492 + $html = preg_replace( '/ *\/?' . '>/', ' ' . $attr_name . '="' . $attr_value . '"$0', $html );
2493 + }
2494 + }
2495 +
2496 + return $html;
2497 + }
2498 +
2499 + public static function mb_convert_encoding_ucs2_utf8( array $match ) {
2500 +
2501 + return mb_convert_encoding( pack( 'H*', $match[ 1 ] ), $to_encoding = 'UTF-8', $from_encoding = 'UCS-2' );
2502 + }
2503 +
2504 + public static function mb_decode_numericentity_utf8( array $match ) {
2505 +
2506 + $convmap = array( 0x0, 0x10000, 0, 0xfffff );
2507 +
2508 + return mb_decode_numericentity( $match[ 0 ], $convmap, 'UTF-8' );
2509 + }
2510 +
2511 + public static function minify_css( $css_data, $filter_prefix = 'sucom' ) {
2512 +
2513 + if ( ! empty( $css_data ) ) { // Make sure we have something to minify.
2514 +
2515 + $classname = apply_filters( $filter_prefix . '_load_lib', false, 'ext/compressor', 'SuextMinifyCssCompressor' );
2516 +
2517 + if ( 'SuextMinifyCssCompressor' === $classname && class_exists( $classname ) ) {
2518 +
2519 + $css_data = $classname::process( $css_data );
2520 + }
2521 + }
2522 +
2523 + return $css_data;
2524 + }
2525 +
2526 + /*
2527 + * Decode Facebook video URLs.
2528 + */
2529 + public static function replace_unicode_escape( $str ) {
2530 +
2531 + if ( function_exists( 'mb_convert_encoding' ) ) {
2532 +
2533 + return preg_replace_callback( '/\\\\u([0-9a-f]{4})/i', array( __CLASS__, 'mb_convert_encoding_ucs2_utf8' ), $str );
2534 + }
2535 +
2536 + return $str;
2537 + }
2538 +
2539 + /*
2540 + * Unchecked checkboxes are not submitted, so re-create them based on hidden form values.
2541 + */
2542 + public static function restore_checkboxes( $opts ) {
2543 +
2544 + if ( is_array( $opts ) ) { // Just in case.
2545 +
2546 + $checkbox = self::preg_grep_keys( '/^is_checkbox_/', $opts, $invert = false, $replace = '' );
2547 +
2548 + foreach ( $checkbox as $key => $val ) {
2549 +
2550 + if ( ! array_key_exists( $key, $opts ) ) {
2551 +
2552 + $opts[ $key ] = 0; // Add missing checkbox as empty.
2553 + }
2554 +
2555 + unset( $opts[ 'is_checkbox_' . $key] );
2556 + }
2557 + }
2558 +
2559 + return $opts;
2560 + }
2561 +
2562 + public static function safe_error_log( $error_msg, $strip_html = false ) {
2563 +
2564 + $ini_safe = array(
2565 + 'display_errors' => 0,
2566 + 'log_errors' => 1,
2567 + 'error_log' => defined( 'WP_DEBUG_LOG' ) && is_string( WP_DEBUG_LOG ) && WP_DEBUG_LOG ?
2568 + WP_DEBUG_LOG : WP_CONTENT_DIR . '/debug.log',
2569 + );
2570 +
2571 + $ini_orig = array();
2572 +
2573 + foreach ( $ini_safe as $name => $value ) {
2574 +
2575 + $value_orig = ini_get( $name ); // Returns false on failure.
2576 +
2577 + if ( $value !== $value_orig ) {
2578 +
2579 + if ( false !== ini_set( $name, $value ) ) { // Returns false on failure.
2580 +
2581 + $ini_orig[ $name ] = $value_orig;
2582 + }
2583 + }
2584 + }
2585 +
2586 + if ( $strip_html ) {
2587 +
2588 + $error_msg = self::strip_html( $error_msg );
2589 + }
2590 +
2591 + /*
2592 + * Use error_log() instead of trigger_error() to avoid HTTP 500.
2593 + */
2594 + error_log( $error_msg );
2595 +
2596 + foreach ( $ini_orig as $name => $value_orig ) {
2597 +
2598 + /*
2599 + * Failed getting the original value.
2600 + */
2601 + if ( false === $value_orig ) {
2602 +
2603 + ini_restore( $name );
2604 +
2605 + /*
2606 + * PHP does not allow setting an empty 'error_log' when ini_get( 'open_basedir' ) is true.
2607 + */
2608 + } elseif ( 'error_log' === $name && empty( $value_orig ) && ini_get( 'open_basedir' ) ) {
2609 +
2610 + ini_restore( $name );
2611 +
2612 + } else ini_set( $name, $value_orig );
2613 + }
2614 + }
2615 +
2616 + public static function strip_html( $text ) {
2617 +
2618 + /*
2619 + * i = Letters in the pattern match both upper and lower case letters.
2620 + * s = A dot metacharacter in the pattern matches all characters, including newlines.
2621 + * U = Invert greediness of quantifiers, so they are NOT greedy by default, but become greedy if followed by ?.
2622 + *
2623 + * See http://php.net/manual/en/reference.pcre.pattern.modifiers.php.
2624 + */
2625 + $text = self::strip_shortcodes( $text ); // Remove any remaining shortcodes.
2626 + $text = preg_replace( '/[\s\n\r]+/s', ' ', $text ); // Put everything on one line.
2627 + $text = preg_replace( '/<\?.*\?' . '>/U', ' ', $text ); // Remove php.
2628 + $text = preg_replace( '/<script\b[^>]*>(.*)<\/script>/Ui', ' ', $text ); // Remove javascript.
2629 + $text = preg_replace( '/<style\b[^>]*>(.*)<\/style>/Ui', ' ', $text ); // Remove inline stylesheets.
2630 + $text = preg_replace( '/([\w])<\/(button|dt|h[0-9]+|li|th)>/i', '$1. ', $text ); // Add missing dot to buttons, headers, lists, etc.
2631 + $text = preg_replace( '/(<p>|<p[^>]+>|<\/p>)/i', ' ', $text ); // Replace paragraph tags with a space.
2632 + $text = trim( strip_tags( $text ) ); // Strip HTML and PHP tags from a string.
2633 + $text = preg_replace( '/(\xC2\xA0|\s)+/s', ' ', $text ); // Replace 1+ spaces to a single space.
2634 +
2635 + return trim( $text );
2636 + }
2637 +
2638 + /*
2639 + * Remove registered shortcodes from the content, along with some known unregistered shortcodes.
2640 + */
2641 + public static function strip_shortcodes( $content ) {
2642 +
2643 + if ( false === strpos( $content, '[' ) ) { // Optimize and check if there are shortcodes.
2644 +
2645 + return $content;
2646 + }
2647 +
2648 + if ( function_exists( 'strip_shortcodes' ) ) {
2649 +
2650 + $content = strip_shortcodes( $content ); // Remove registered shortcodes.
2651 +
2652 + if ( false === strpos( $content, '[' ) ) { // Stop here if there are no more shortcodes.
2653 +
2654 + return $content;
2655 + }
2656 + }
2657 +
2658 + $shortcodes_preg = array( '/\[\/?(cs_element_|et_|fusion_|mk_|rev_slider_|vc_)[^\]]+\]/' );
2659 +
2660 + $content = preg_replace( $shortcodes_preg, ' ', $content );
2661 +
2662 + return $content;
2663 + }
2664 +
2665 + protected static function strnatcasecmp_remove_accents( $a, $b ) {
2666 +
2667 + return strnatcasecmp( remove_accents( $a ), remove_accents( $b ) );
2668 + }
2669 +
2670 + public static function unparse_url( $parsed_url ) {
2671 +
2672 + $scheme = isset( $parsed_url[ 'scheme' ] ) ? $parsed_url[ 'scheme' ] . '://' : '';
2673 + $user = isset( $parsed_url[ 'user' ] ) ? $parsed_url[ 'user' ] : '';
2674 + $pass = isset( $parsed_url[ 'pass' ] ) ? ':' . $parsed_url[ 'pass' ] : '';
2675 + $host = isset( $parsed_url[ 'host' ] ) ? $parsed_url[ 'host' ] : '';
2676 + $port = isset( $parsed_url[ 'port' ] ) ? ':' . $parsed_url[ 'port' ] : '';
2677 + $path = isset( $parsed_url[ 'path' ] ) ? $parsed_url[ 'path' ] : '';
2678 + $query = isset( $parsed_url[ 'query' ] ) ? '?' . $parsed_url[ 'query' ] : '';
2679 + $fragment = isset( $parsed_url[ 'fragment' ] ) ? '#' . $parsed_url[ 'fragment' ] : '';
2680 +
2681 + return $scheme . $user . $pass . ( $user || $pass ? '@' : '' ) . $host . $port . $path . $query . $fragment;
2682 + }
2683 +
2684 + protected static function unquote_csv_value( $val ) {
2685 +
2686 + return trim( $val, '\'" ' ); // Remove quotes and spaces.
2687 + }
2688 +
2689 + public static function update_prot( $url = '' ) {
2690 +
2691 + if ( 0 === strpos( $url, '/' ) ) { // Skip relative URLs.
2692 +
2693 + return $url;
2694 + }
2695 +
2696 + $prot_slash = self::get_prot() . '://';
2697 +
2698 + if ( 0 === strpos( $url, $prot_slash ) ) { // Skip correct URLs.
2699 +
2700 + return $url;
2701 + }
2702 +
2703 + return preg_replace( '/^([a-z]+:\/\/)/', $prot_slash, $url );
2704 + }
2705 + }
2706 +}