PluginProbe
StreamCast – bring live radio to your site with a sleek player / 2.2.1
StreamCast – bring live radio to your site with a sleek player v2.2.1
2.4.5 2.4.4 trunk 1.0 1.1 2.0.0 2.1.10 2.1.2 2.1.4 2.1.5 2.1.8 2.2.1 2.2.3 2.2.4 2.2.5 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.3.5 2.3.6 2.3.7 2.3.8 2.3.9 All 29 releases
streamcast / freemius / includes / fs-core-functions.php

fs-core-functions.php in StreamCast – bring live radio to your site with a sleek player 2.2.1, at freemius/includes/fs-core-functions.php

1,461 lines 51.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package Freemius
4 * @copyright Copyright (c) 2015, Freemius, Inc.
5 * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
6 * @since 1.0.3
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 if ( ! function_exists( 'fs_dummy' ) ) {
14 function fs_dummy() {
15 }
16 }
17
18 /* Url.
19 --------------------------------------------------------------------------------------------*/
20 if ( ! function_exists( 'fs_get_url_daily_cache_killer' ) ) {
21 function fs_get_url_daily_cache_killer() {
22 return date( '\YY\Mm\Dd' );
23 }
24 }
25
26 /* Templates / Views.
27 --------------------------------------------------------------------------------------------*/
28 if ( ! function_exists( 'fs_get_template_path' ) ) {
29 function fs_get_template_path( $path ) {
30 return WP_FS__DIR_TEMPLATES . '/' . trim( $path, '/' );
31 }
32
33 function fs_include_template( $path, &$params = null ) {
34 $VARS = &$params;
35 include fs_get_template_path( $path );
36 }
37
38 function fs_include_once_template( $path, &$params = null ) {
39 $VARS = &$params;
40 include_once fs_get_template_path( $path );
41 }
42
43 function fs_require_template( $path, &$params = null ) {
44 $VARS = &$params;
45 require fs_get_template_path( $path );
46 }
47
48 function fs_require_once_template( $path, &$params = null ) {
49 $VARS = &$params;
50 require_once fs_get_template_path( $path );
51 }
52
53 function fs_get_template( $path, &$params = null ) {
54 ob_start();
55
56 $VARS = &$params;
57 require fs_get_template_path( $path );
58
59 return ob_get_clean();
60 }
61 }
62
63 /* Scripts and styles including.
64 --------------------------------------------------------------------------------------------*/
65
66 if ( ! function_exists( 'fs_asset_url' ) ) {
67 /**
68 * Generates an absolute URL to the given path. This function ensures that the URL will be correct whether the asset
69 * is inside a plugin's folder or a theme's folder.
70 *
71 * Examples:
72 * 1. "themes" folder
73 * Path: C:/xampp/htdocs/fswp/wp-content/themes/twentytwelve/freemius/assets/css/admin/common.css
74 * URL: http://fswp:8080/wp-content/themes/twentytwelve/freemius/assets/css/admin/common.css
75 *
76 * 2. "plugins" folder
77 * Path: C:/xampp/htdocs/fswp/wp-content/plugins/rating-widget-premium/freemius/assets/css/admin/common.css
78 * URL: http://fswp:8080/wp-content/plugins/rating-widget-premium/freemius/assets/css/admin/common.css
79 *
80 * @author Leo Fajardo (@leorw)
81 * @since 1.2.2
82 *
83 * @param string $asset_abs_path Asset's absolute path.
84 *
85 * @return string Asset's URL.
86 */
87 function fs_asset_url( $asset_abs_path ) {
88 $wp_content_dir = fs_normalize_path( WP_CONTENT_DIR );
89 $asset_abs_path = fs_normalize_path( $asset_abs_path );
90
91 if ( 0 === strpos( $asset_abs_path, $wp_content_dir ) ) {
92 // Handle both theme and plugin assets located in the standard directories.
93 $asset_rel_path = str_replace( $wp_content_dir, '', $asset_abs_path );
94 $asset_url = content_url( fs_normalize_path( $asset_rel_path ) );
95 } else {
96 $wp_plugins_dir = fs_normalize_path( WP_PLUGIN_DIR );
97 if ( 0 === strpos( $asset_abs_path, $wp_plugins_dir ) ) {
98 // Try to handle plugin assets that may be located in a non-standard plugins directory.
99 $asset_rel_path = str_replace( $wp_plugins_dir, '', $asset_abs_path );
100 $asset_url = plugins_url( fs_normalize_path( $asset_rel_path ) );
101 } else {
102 // Try to handle theme assets that may be located in a non-standard themes directory.
103 $active_theme_stylesheet = get_stylesheet();
104 $wp_themes_dir = fs_normalize_path( trailingslashit( get_theme_root( $active_theme_stylesheet ) ) );
105 $asset_rel_path = str_replace( $wp_themes_dir, '', fs_normalize_path( $asset_abs_path ) );
106 $asset_url = trailingslashit( get_theme_root_uri( $active_theme_stylesheet ) ) . fs_normalize_path( $asset_rel_path );
107 }
108 }
109
110 return $asset_url;
111 }
112 }
113
114 if ( ! function_exists( 'fs_enqueue_local_style' ) ) {
115 function fs_enqueue_local_style( $handle, $path, $deps = array(), $ver = false, $media = 'all' ) {
116 wp_enqueue_style( $handle, fs_asset_url( WP_FS__DIR_CSS . '/' . trim( $path, '/' ) ), $deps, $ver, $media );
117 }
118 }
119
120 if ( ! function_exists( 'fs_enqueue_local_script' ) ) {
121 function fs_enqueue_local_script( $handle, $path, $deps = array(), $ver = false, $in_footer = 'all' ) {
122 wp_enqueue_script( $handle, fs_asset_url( WP_FS__DIR_JS . '/' . trim( $path, '/' ) ), $deps, $ver, $in_footer );
123 }
124 }
125
126 if ( ! function_exists( 'fs_img_url' ) ) {
127 function fs_img_url( $path, $img_dir = WP_FS__DIR_IMG ) {
128 return ( fs_asset_url( $img_dir . '/' . trim( $path, '/' ) ) );
129 }
130 }
131
132 #--------------------------------------------------------------------------------
133 #region Request handlers.
134 #--------------------------------------------------------------------------------
135
136 if ( ! function_exists( 'fs_request_get_raw' ) ) {
137 /**
138 * A helper function to fetch GET/POST user input with an optional default value when the input is not set.
139 * This function does not do sanitization. It is up to the caller to properly sanitize and validate the input.
140 *
141 * The return of this function is always unslashed.
142 *
143 * @since 2.5.10
144 *
145 * @param string $key
146 * @param mixed $def
147 * @param string|bool $type When set to 'get', it will look for the value passed via query string. When
148 * set to 'post', it will look for the value passed via the POST request's body. Otherwise,
149 * it will check if the parameter was passed using any of the mentioned two methods.
150 *
151 * @return mixed
152 */
153 function fs_request_get_raw( $key, $def = false, $type = false ) {
154 if ( is_string( $type ) ) {
155 $type = strtolower( $type );
156 }
157
158 /**
159 * Note to WordPress.org reviewers:
160 * This is a helper function to fetch GET/POST user input with an optional default value when the input is not set. The actual sanitization is done in the scope of the function's usage.
161 */
162 switch ( $type ) {
163 case 'post':
164 // phpcs:ignore WordPress.Security.NonceVerification.Missing
165 $value = isset( $_POST[ $key ] ) ? $_POST[ $key ] : $def;
166 break;
167 case 'get':
168 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
169 $value = isset( $_GET[ $key ] ) ? $_GET[ $key ] : $def;
170 break;
171 default:
172 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
173 $value = isset( $_REQUEST[ $key ] ) ? $_REQUEST[ $key ] : $def;
174 break;
175 }
176
177 // Don't unslash if the value itself is empty (empty string, null, empty array etc).
178 return empty( $value ) ? $value : wp_unslash( $value );
179 }
180 }
181
182 if ( ! function_exists( 'fs_sanitize_input' ) ) {
183 /**
184 * Sanitizes input recursively (if an array).
185 *
186 * @param mixed $input
187 *
188 * @return mixed
189 * @uses sanitize_text_field()
190 * @since 2.5.10
191 */
192 function fs_sanitize_input( $input ) {
193 if ( is_array( $input ) ) {
194 foreach ( $input as $key => $value ) {
195 $input[ $key ] = fs_sanitize_input( $value );
196 }
197 } else {
198 // Allow empty values to pass through as-is, like `null`, `''`, `0`, `'0'` etc.
199 $input = empty( $input ) ? $input : sanitize_text_field( $input );
200 }
201
202 return $input;
203 }
204 }
205
206 if ( ! function_exists( 'fs_request_get' ) ) {
207 /**
208 * A helper method to fetch GET/POST user input with an optional default value when the input is not set.
209 *
210 * @author Vova Feldman (@svovaf)
211 *
212 * @note The return value is always sanitized with sanitize_text_field().
213 *
214 * @param string $key
215 * @param mixed $def
216 * @param string|bool $type Since 1.2.1.7 - when set to 'get' will look for the value passed via querystring, when
217 * set to 'post' will look for the value passed via the POST request's body, otherwise,
218 * will check if the parameter was passed in any of the two.
219 *
220 *
221 * @return mixed
222 */
223 function fs_request_get( $key, $def = false, $type = false ) {
224 return fs_sanitize_input( fs_request_get_raw( $key, $def, $type ) );
225 }
226 }
227
228 if ( ! function_exists( 'fs_request_has' ) ) {
229 function fs_request_has( $key ) {
230 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
231 return isset( $_REQUEST[ $key ] );
232 }
233 }
234
235 if ( ! function_exists( 'fs_request_get_bool' ) ) {
236 /**
237 * A helper method to fetch GET/POST user boolean input with an optional default value when the input is not set.
238 *
239 * @author Vova Feldman (@svovaf)
240 *
241 * @param string $key
242 * @param bool $def
243 *
244 * @return bool|mixed
245 */
246 function fs_request_get_bool( $key, $def = false ) {
247 $val = fs_request_get( $key, null );
248
249 if ( is_null( $val ) ) {
250 return $def;
251 }
252
253 if ( is_bool( $val ) ) {
254 return $val;
255 } else if ( is_numeric( $val ) ) {
256 if ( 1 == $val ) {
257 return true;
258 } else if ( 0 == $val ) {
259 return false;
260 }
261 } else if ( is_string( $val ) ) {
262 $val = strtolower( $val );
263
264 if ( 'true' === $val ) {
265 return true;
266 } else if ( 'false' === $val ) {
267 return false;
268 }
269 }
270
271 return $def;
272 }
273 }
274
275 if ( ! function_exists( 'fs_request_is_post' ) ) {
276 function fs_request_is_post() {
277 return ( 'post' === strtolower( $_SERVER['REQUEST_METHOD'] ) );
278 }
279 }
280
281 if ( ! function_exists( 'fs_request_is_get' ) ) {
282 function fs_request_is_get() {
283 return ( 'get' === strtolower( $_SERVER['REQUEST_METHOD'] ) );
284 }
285 }
286
287 if ( ! function_exists( 'fs_get_action' ) ) {
288 function fs_get_action( $action_key = 'action' ) {
289 // phpcs:disable WordPress.Security.NonceVerification.Recommended
290 if ( ! empty( $_REQUEST[ $action_key ] ) && is_string( $_REQUEST[ $action_key ] ) ) {
291 return strtolower( $_REQUEST[ $action_key ] );
292 }
293
294 if ( 'action' == $action_key ) {
295 $action_key = 'fs_action';
296
297 if ( ! empty( $_REQUEST[ $action_key ] ) && is_string( $_REQUEST[ $action_key ] ) ) {
298 return strtolower( $_REQUEST[ $action_key ] );
299 }
300 }
301
302 return false;
303 // phpcs:enable WordPress.Security.NonceVerification.Recommended
304 }
305 }
306
307 if ( ! function_exists( 'fs_request_is_action' ) ) {
308 function fs_request_is_action( $action, $action_key = 'action' ) {
309 return ( strtolower( $action ) === fs_get_action( $action_key ) );
310 }
311 }
312
313 if ( ! function_exists( 'fs_request_is_action_secure' ) ) {
314 /**
315 * @author Vova Feldman (@svovaf)
316 * @since 1.0.0
317 *
318 * @since 1.2.1.5 Allow nonce verification.
319 *
320 * @param string $action
321 * @param string $action_key
322 * @param string $nonce_key
323 *
324 * @return bool
325 */
326 function fs_request_is_action_secure(
327 $action,
328 $action_key = 'action',
329 $nonce_key = 'nonce'
330 ) {
331 if ( strtolower( $action ) !== fs_get_action( $action_key ) ) {
332 return false;
333 }
334
335 $nonce = ! empty( $_REQUEST[ $nonce_key ] ) ?
336 $_REQUEST[ $nonce_key ] :
337 '';
338
339 if ( empty( $nonce ) ||
340 ( false === wp_verify_nonce( $nonce, $action ) )
341 ) {
342 return false;
343 }
344
345 return true;
346 }
347 }
348
349 #endregion
350
351 if ( ! function_exists( 'fs_is_plugin_page' ) ) {
352 function fs_is_plugin_page( $page_slug ) {
353 return ( is_admin() && $page_slug === fs_request_get( 'page' ) );
354 }
355 }
356
357 if ( ! function_exists( 'fs_get_raw_referer' ) ) {
358 /**
359 * Retrieves unvalidated referer from '_wp_http_referer' or HTTP referer.
360 *
361 * Do not use for redirects, use {@see wp_get_referer()} instead.
362 *
363 * @since 1.2.3
364 *
365 * @return string|false Referer URL on success, false on failure.
366 */
367 function fs_get_raw_referer() {
368 if ( function_exists( 'wp_get_raw_referer' ) ) {
369 return wp_get_raw_referer();
370 }
371 if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
372 return wp_unslash( $_REQUEST['_wp_http_referer'] );
373 } else if ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
374 return wp_unslash( $_SERVER['HTTP_REFERER'] );
375 }
376
377 return false;
378 }
379 }
380
381 /* Core UI.
382 --------------------------------------------------------------------------------------------*/
383 if ( ! function_exists( 'fs_ui_action_button' ) ) {
384 /**
385 * @param number $module_id
386 * @param string $page
387 * @param string $action
388 * @param string $title
389 * @param string $button_class
390 * @param array $params
391 * @param bool $is_primary
392 * @param bool $is_small
393 * @param string|bool $icon_class Optional class for an icon (since 1.1.7).
394 * @param string|bool $confirmation Optional confirmation message before submit (since 1.1.7).
395 * @param string $method Since 1.1.7
396 *
397 * @uses fs_ui_get_action_button()
398 */
399 function fs_ui_action_button(
400 $module_id,
401 $page,
402 $action,
403 $title,
404 $button_class = '',
405 $params = array(),
406 $is_primary = true,
407 $is_small = false,
408 $icon_class = false,
409 $confirmation = false,
410 $method = 'GET'
411 ) {
412 echo fs_ui_get_action_button(
413 $module_id,
414 $page,
415 $action,
416 $title,
417 $button_class,
418 $params,
419 $is_primary,
420 $is_small,
421 $icon_class,
422 $confirmation,
423 $method
424 );
425 }
426 }
427
428 if ( ! function_exists( 'fs_ui_get_action_button' ) ) {
429 /**
430 * @author Vova Feldman (@svovaf)
431 * @since 1.1.7
432 *
433 * @param number $module_id
434 * @param string $page
435 * @param string $action
436 * @param string $title
437 * @param string $button_class
438 * @param array $params
439 * @param bool $is_primary
440 * @param bool $is_small
441 * @param string|bool $icon_class Optional class for an icon.
442 * @param string|bool $confirmation Optional confirmation message before submit.
443 * @param string $method
444 *
445 * @return string
446 */
447 function fs_ui_get_action_button(
448 $module_id,
449 $page,
450 $action,
451 $title,
452 $button_class = '',
453 $params = array(),
454 $is_primary = true,
455 $is_small = false,
456 $icon_class = false,
457 $confirmation = false,
458 $method = 'GET'
459 ) {
460 // Prepend icon (if set).
461 $title = ( is_string( $icon_class ) ? '<i class="' . $icon_class . '"></i> ' : '' ) . $title;
462
463 if ( is_string( $confirmation ) ) {
464 return sprintf( '<form action="%s" method="%s"><input type="hidden" name="fs_action" value="%s">%s<a href="#" class="%s" onclick="if (confirm(\'%s\')) this.parentNode.submit(); return false;">%s</a></form>',
465 freemius( $module_id )->_get_admin_page_url( $page, $params ),
466 $method,
467 $action,
468 wp_nonce_field( $action, '_wpnonce', true, false ),
469 'button' . ( ! empty( $button_class ) ? ' ' . $button_class : '' ) . ( $is_primary ? ' button-primary' : '' ) . ( $is_small ? ' button-small' : '' ),
470 $confirmation,
471 $title
472 );
473 } else if ( 'GET' !== strtoupper( $method ) ) {
474 return sprintf( '<form action="%s" method="%s"><input type="hidden" name="fs_action" value="%s">%s<a href="#" class="%s" onclick="this.parentNode.submit(); return false;">%s</a></form>',
475 freemius( $module_id )->_get_admin_page_url( $page, $params ),
476 $method,
477 $action,
478 wp_nonce_field( $action, '_wpnonce', true, false ),
479 'button' . ( ! empty( $button_class ) ? ' ' . $button_class : '' ) . ( $is_primary ? ' button-primary' : '' ) . ( $is_small ? ' button-small' : '' ),
480 $title
481 );
482 } else {
483 return sprintf( '<a href="%s" class="%s">%s</a></form>',
484 wp_nonce_url( freemius( $module_id )->_get_admin_page_url( $page, array_merge( $params, array( 'fs_action' => $action ) ) ), $action ),
485 'button' . ( ! empty( $button_class ) ? ' ' . $button_class : '' ) . ( $is_primary ? ' button-primary' : '' ) . ( $is_small ? ' button-small' : '' ),
486 $title
487 );
488 }
489 }
490
491 function fs_ui_action_link( $module_id, $page, $action, $title, $params = array() ) {
492 ?><a class=""
493 href="<?php echo wp_nonce_url( freemius( $module_id )->_get_admin_page_url( $page, array_merge( $params, array( 'fs_action' => $action ) ) ), $action ) ?>"><?php echo $title ?></a><?php
494 }
495 }
496
497 if ( ! function_exists( 'fs_get_entity' ) ) {
498 /**
499 * @author Leo Fajardo (@leorw)
500 * @since 2.3.1
501 *
502 * @param mixed $entity
503 * @param string $class
504 *
505 * @return FS_Plugin|FS_User|FS_Site|FS_Plugin_License|FS_Plugin_Plan|FS_Plugin_Tag|FS_Subscription
506 */
507 function fs_get_entity( $entity, $class ) {
508 if ( ! is_object( $entity ) || $entity instanceof $class ) {
509 return $entity;
510 }
511
512 return new $class( $entity );
513 }
514 }
515
516 if ( ! function_exists( 'fs_get_entities' ) ) {
517 /**
518 * @author Leo Fajardo (@leorw)
519 * @since 2.3.1
520 *
521 * @param mixed $entities
522 * @param string $class_name
523 *
524 * @return FS_Plugin[]|FS_User[]|FS_Site[]|FS_Plugin_License[]|FS_Plugin_Plan[]|FS_Plugin_Tag[]|FS_Subscription[]
525 */
526 function fs_get_entities( $entities, $class_name ) {
527 if ( ! is_array( $entities ) || empty( $entities ) ) {
528 return $entities;
529 }
530
531 // Get first element.
532 $first_array_element = reset( $entities );
533
534 if ( $first_array_element instanceof $class_name ) {
535 /**
536 * If the first element of the array is an instance of the context class, assume that all other
537 * elements are instances of the class.
538 */
539 return $entities;
540 }
541
542 if (
543 is_array( $first_array_element ) &&
544 ! empty( $first_array_element )
545 ) {
546 $first_array_element = reset( $first_array_element );
547
548 if ( $first_array_element instanceof $class_name ) {
549 /**
550 * If the first element of the `$entities` array is an array whose first element is an instance of the
551 * context class, assume that all other objects are instances of the class.
552 */
553 return $entities;
554 }
555 }
556
557 foreach ( $entities as $key => $entities_or_entity ) {
558 if ( is_array( $entities_or_entity ) ) {
559 $entities[ $key ] = fs_get_entities( $entities_or_entity, $class_name );
560 } else {
561 $entities[ $key ] = fs_get_entity( $entities_or_entity, $class_name );
562 }
563 }
564
565 return $entities;
566 }
567 }
568
569 if ( ! function_exists( 'fs_nonce_url' ) ) {
570 /**
571 * Retrieve URL with nonce added to URL query.
572 *
573 * Originally was using `wp_nonce_url()` but the new version
574 * changed the return value to escaped URL, that's not the expected
575 * behaviour.
576 *
577 * @author Vova Feldman (@svovaf)
578 * @since ~1.1.3
579 *
580 * @param string $actionurl URL to add nonce action.
581 * @param int|string $action Optional. Nonce action name. Default -1.
582 * @param string $name Optional. Nonce name. Default '_wpnonce'.
583 *
584 * @return string Escaped URL with nonce action added.
585 */
586 function fs_nonce_url( $actionurl, $action = - 1, $name = '_wpnonce' ) {
587 return add_query_arg( $name, wp_create_nonce( $action ), $actionurl );
588 }
589 }
590
591 if ( ! function_exists( 'fs_starts_with' ) ) {
592 /**
593 * Check if string starts with.
594 *
595 * @author Vova Feldman (@svovaf)
596 * @since 1.1.3
597 *
598 * @param string $haystack
599 * @param string $needle
600 *
601 * @return bool
602 */
603 function fs_starts_with( $haystack, $needle ) {
604 $length = strlen( $needle );
605
606 return ( substr( $haystack, 0, $length ) === $needle );
607 }
608 }
609
610 if ( ! function_exists( 'fs_ends_with' ) ) {
611 /**
612 * Check if string ends with.
613 *
614 * @author Vova Feldman (@svovaf)
615 * @since 2.0.0
616 *
617 * @param string $haystack
618 * @param string $needle
619 *
620 * @return bool
621 */
622 function fs_ends_with( $haystack, $needle ) {
623 $length = strlen( $needle );
624 $start = $length * - 1; // negative
625
626 return ( substr( $haystack, $start ) === $needle );
627 }
628 }
629
630 if ( ! function_exists( 'fs_strip_url_protocol' ) ) {
631 function fs_strip_url_protocol( $url ) {
632 if ( ! fs_starts_with( $url, 'http' ) ) {
633 return $url;
634 }
635
636 $protocol_pos = strpos( $url, '://' );
637
638 if ( $protocol_pos > 5 ) {
639 return $url;
640 }
641
642 return substr( $url, $protocol_pos + 3 );
643 }
644 }
645
646 #region Url Canonization ------------------------------------------------------------------
647
648 if ( ! function_exists( 'fs_canonize_url' ) ) {
649 /**
650 * @author Vova Feldman (@svovaf)
651 * @since 1.1.3
652 *
653 * @param string $url
654 * @param bool $omit_host
655 * @param array $ignore_params
656 *
657 * @return string
658 */
659 function fs_canonize_url( $url, $omit_host = false, $ignore_params = array() ) {
660 $parsed_url = parse_url( strtolower( $url ) );
661
662 // if ( ! isset( $parsed_url['host'] ) ) {
663 // return $url;
664 // }
665
666 $canonical = ( ( $omit_host || ! isset( $parsed_url['host'] ) ) ? '' : $parsed_url['host'] ) . $parsed_url['path'];
667
668 if ( isset( $parsed_url['query'] ) ) {
669 parse_str( $parsed_url['query'], $queryString );
670 $canonical .= '?' . fs_canonize_query_string( $queryString, $ignore_params );
671 }
672
673 return $canonical;
674 }
675 }
676
677 if ( ! function_exists( 'fs_canonize_query_string' ) ) {
678 /**
679 * @author Vova Feldman (@svovaf)
680 * @since 1.1.3
681 *
682 * @param array $params
683 * @param array $ignore_params
684 * @param bool $params_prefix
685 *
686 * @return string
687 */
688 function fs_canonize_query_string( array $params, array &$ignore_params, $params_prefix = false ) {
689 if ( ! is_array( $params ) || 0 === count( $params ) ) {
690 return '';
691 }
692
693 // Url encode both keys and values
694 $keys = fs_urlencode_rfc3986( array_keys( $params ) );
695 $values = fs_urlencode_rfc3986( array_values( $params ) );
696 $params = array_combine( $keys, $values );
697
698 // Parameters are sorted by name, using lexicographical byte value ordering.
699 // Ref: Spec: 9.1.1 (1)
700 uksort( $params, 'strcmp' );
701
702 $pairs = array();
703 foreach ( $params as $parameter => $value ) {
704 $lower_param = strtolower( $parameter );
705
706 // Skip ignore params.
707 if ( in_array( $lower_param, $ignore_params ) ||
708 ( false !== $params_prefix && fs_starts_with( $lower_param, $params_prefix ) )
709 ) {
710 continue;
711 }
712
713 if ( is_array( $value ) ) {
714 // If two or more parameters share the same name, they are sorted by their value
715 // Ref: Spec: 9.1.1 (1)
716 natsort( $value );
717 foreach ( $value as $duplicate_value ) {
718 $pairs[] = $lower_param . '=' . $duplicate_value;
719 }
720 } else {
721 $pairs[] = $lower_param . '=' . $value;
722 }
723 }
724
725 if ( 0 === count( $pairs ) ) {
726 return '';
727 }
728
729 return implode( "&", $pairs );
730 }
731 }
732
733 if ( ! function_exists( 'fs_urlencode_rfc3986' ) ) {
734 /**
735 * @author Vova Feldman (@svovaf)
736 * @since 1.1.3
737 *
738 * @param string|string[] $input
739 *
740 * @return array|mixed|string
741 */
742 function fs_urlencode_rfc3986( $input ) {
743 if ( is_array( $input ) ) {
744 return array_map( 'fs_urlencode_rfc3986', $input );
745 } else if ( is_scalar( $input ) ) {
746 return str_replace( '+', ' ', str_replace( '%7E', '~', rawurlencode( $input ) ) );
747 }
748
749 return '';
750 }
751 }
752
753 #endregion Url Canonization ------------------------------------------------------------------
754
755 if ( ! function_exists( 'fs_download_image' ) ) {
756 /**
757 * @author Vova Feldman (@svovaf)
758 *
759 * @since 1.2.2 Changed to usage of WP_Filesystem_Direct.
760 *
761 * @param string $from URL
762 * @param string $to File path.
763 *
764 * @return bool Is successfully downloaded.
765 */
766 function fs_download_image( $from, $to ) {
767 $dir = dirname( $to );
768
769 if ( 'direct' !== get_filesystem_method( array(), $dir ) ) {
770 return false;
771 }
772
773 if ( ! class_exists( 'WP_Filesystem_Direct' ) ) {
774 require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
775 require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php';
776 }
777
778 $fs = new WP_Filesystem_Direct( '' );
779 $tmpfile = download_url( $from );
780
781 if ( $tmpfile instanceof WP_Error ) {
782 // Issue downloading the file.
783 return false;
784 }
785
786 $fs->copy( $tmpfile, $to );
787 $fs->delete( $tmpfile );
788
789 return true;
790 }
791 }
792
793 /* General Utilities
794 --------------------------------------------------------------------------------------------*/
795
796 if ( ! function_exists( 'fs_sort_by_priority' ) ) {
797 /**
798 * Sorts an array by the value of the priority key.
799 *
800 * @author Daniel Iser (@danieliser)
801 * @since 1.1.7
802 *
803 * @param $a
804 * @param $b
805 *
806 * @return int
807 */
808 function fs_sort_by_priority( $a, $b ) {
809
810 // If b has a priority and a does not, b wins.
811 if ( ! isset( $a['priority'] ) && isset( $b['priority'] ) ) {
812 return 1;
813 } // If b has a priority and a does not, b wins.
814 elseif ( isset( $a['priority'] ) && ! isset( $b['priority'] ) ) {
815 return - 1;
816 } // If neither has a priority or both priorities are equal it's a tie.
817 elseif ( ( ! isset( $a['priority'] ) && ! isset( $b['priority'] ) ) || $a['priority'] === $b['priority'] ) {
818 return 0;
819 }
820
821 // If both have priority return the winner.
822 return ( $a['priority'] < $b['priority'] ) ? - 1 : 1;
823 }
824 }
825
826 #--------------------------------------------------------------------------------
827 #region Localization
828 #--------------------------------------------------------------------------------
829
830 global $fs_text_overrides;
831
832 if ( ! isset( $fs_text_overrides ) ) {
833 $fs_text_overrides = array();
834 }
835
836 if ( ! function_exists( 'fs_text' ) ) {
837 /**
838 * Retrieve a translated text by key.
839 *
840 * @author Vova Feldman (@svovaf)
841 * @since 1.2.1.7
842 *
843 * @param string $key
844 * @param string $slug
845 *
846 * @return string
847 *
848 * @global $fs_text_overrides
849 */
850 function fs_text( $key, $slug = 'freemius' ) {
851 global $fs_text_overrides;
852
853 if ( isset( $fs_text_overrides[ $slug ] ) ) {
854 if ( isset( $fs_text_overrides[ $slug ][ $key ] ) ) {
855 return $fs_text_overrides[ $slug ][ $key ];
856 }
857
858 $lower_key = strtolower( $key );
859 if ( isset( $fs_text_overrides[ $slug ][ $lower_key ] ) ) {
860 return $fs_text_overrides[ $slug ][ $lower_key ];
861 }
862 }
863
864 return $key;
865 }
866
867 #region Private
868
869 /**
870 * Retrieve an inline translated text by key with a context.
871 *
872 * @author Vova Feldman (@svovaf)
873 * @since 1.2.3
874 *
875 * @param string $text Translatable string.
876 * @param string $context Context information for the translators.
877 * @param string $key String key for overrides.
878 * @param string $slug Module slug for overrides.
879 *
880 * @return string
881 *
882 * @global $fs_text_overrides
883 */
884 function _fs_text_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
885 list( $text, $text_domain ) = fs_text_and_domain( $text, $key, $slug );
886
887 // Avoid misleading Theme Check warning.
888 $fn = 'translate_with_gettext_context';
889
890 return $fn( $text, $context, $text_domain );
891 }
892
893 #endregion
894
895 /**
896 * Retrieve an inline translated text by key with a context.
897 *
898 * @author Vova Feldman (@svovaf)
899 * @since 1.2.3
900 *
901 * @param string $text Translatable string.
902 * @param string $context Context information for the translators.
903 * @param string $key String key for overrides.
904 * @param string $slug Module slug for overrides.
905 *
906 * @return string
907 *
908 * @global $fs_text_overrides
909 */
910 function fs_text_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
911 return _fs_text_x_inline( $text, $context, $key, $slug );
912 }
913
914 /**
915 * Output a translated text by key.
916 *
917 * @author Vova Feldman (@svovaf)
918 * @since 1.2.1.7
919 *
920 * @param string $key
921 * @param string $slug
922 */
923 function fs_echo( $key, $slug = 'freemius' ) {
924 echo fs_text( $key, $slug );
925 }
926
927 /**
928 * Output an inline translated text.
929 *
930 * @author Vova Feldman (@svovaf)
931 * @since 1.2.3
932 *
933 * @param string $text Translatable string.
934 * @param string $key String key for overrides.
935 * @param string $slug Module slug for overrides.
936 */
937 function fs_echo_inline( $text, $key = '', $slug = 'freemius' ) {
938 echo _fs_text_inline( $text, $key, $slug );
939 }
940
941 /**
942 * Output an inline translated text with a context.
943 *
944 * @author Vova Feldman (@svovaf)
945 * @since 1.2.3
946 *
947 * @param string $text Translatable string.
948 * @param string $context Context information for the translators.
949 * @param string $key String key for overrides.
950 * @param string $slug Module slug for overrides.
951 */
952 function fs_echo_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
953 echo _fs_text_x_inline( $text, $context, $key, $slug );
954 }
955 }
956
957 if ( ! function_exists( 'fs_text_override' ) ) {
958 /**
959 * Get a translatable text override if exists, or `false`.
960 *
961 * @author Vova Feldman (@svovaf)
962 * @since 1.2.1.7
963 *
964 * @param string $text Translatable string.
965 * @param string $key String key for overrides.
966 * @param string $slug Module slug for overrides.
967 *
968 * @return string|false
969 */
970 function fs_text_override( $text, $key, $slug ) {
971 global $fs_text_overrides;
972
973 /**
974 * Check if string is overridden.
975 */
976 if ( ! isset( $fs_text_overrides[ $slug ] ) ) {
977 return false;
978 }
979
980 if ( empty( $key ) ) {
981 $key = strtolower( str_replace( ' ', '-', $text ) );
982 }
983
984 if ( isset( $fs_text_overrides[ $slug ][ $key ] ) ) {
985 return $fs_text_overrides[ $slug ][ $key ];
986 }
987
988 $lower_key = strtolower( $key );
989 if ( isset( $fs_text_overrides[ $slug ][ $lower_key ] ) ) {
990 return $fs_text_overrides[ $slug ][ $lower_key ];
991 }
992
993 return false;
994 }
995 }
996
997 if ( ! function_exists( 'fs_text_and_domain' ) ) {
998 /**
999 * Get a translatable text and its text domain.
1000 *
1001 * When the text is overridden by the module, returns the overridden text and the text domain of the module. Otherwise, returns the original text and 'freemius' as the text domain.
1002 *
1003 * @author Vova Feldman (@svovaf)
1004 * @since 1.2.1.7
1005 *
1006 * @param string $text Translatable string.
1007 * @param string $key String key for overrides.
1008 * @param string $slug Module slug for overrides.
1009 *
1010 * @return string[]
1011 */
1012 function fs_text_and_domain( $text, $key, $slug ) {
1013 $override = fs_text_override( $text, $key, $slug );
1014
1015 if ( false === $override ) {
1016 // No override, use FS text domain.
1017 $text_domain = 'freemius';
1018 } else {
1019 // Found an override.
1020 $text = $override;
1021 // Use the module's text domain.
1022 $text_domain = $slug;
1023 }
1024
1025 return array( $text, $text_domain );
1026 }
1027 }
1028
1029 if ( ! function_exists( '_fs_text_inline' ) ) {
1030 /**
1031 * Retrieve an inline translated text by key.
1032 *
1033 * @author Vova Feldman (@svovaf)
1034 * @since 1.2.3
1035 *
1036 * @param string $text Translatable string.
1037 * @param string $key String key for overrides.
1038 * @param string $slug Module slug for overrides.
1039 *
1040 * @return string
1041 *
1042 * @global $fs_text_overrides
1043 */
1044 function _fs_text_inline( $text, $key = '', $slug = 'freemius' ) {
1045 list( $text, $text_domain ) = fs_text_and_domain( $text, $key, $slug );
1046
1047 // Avoid misleading Theme Check warning.
1048 $fn = 'translate';
1049
1050 return $fn( $text, $text_domain );
1051 }
1052 }
1053
1054 if ( ! function_exists( 'fs_text_inline' ) ) {
1055 /**
1056 * Retrieve an inline translated text by key.
1057 *
1058 * @author Vova Feldman (@svovaf)
1059 * @since 1.2.3
1060 *
1061 * @param string $text Translatable string.
1062 * @param string $key String key for overrides.
1063 * @param string $slug Module slug for overrides.
1064 *
1065 * @return string
1066 *
1067 * @global $fs_text_overrides
1068 */
1069 function fs_text_inline( $text, $key = '', $slug = 'freemius' ) {
1070 return _fs_text_inline( $text, $key, $slug );
1071 }
1072 }
1073
1074 if ( ! function_exists( 'fs_esc_attr' ) ) {
1075 /**
1076 * @author Vova Feldman
1077 * @since 1.2.1.6
1078 *
1079 * @param string $key
1080 * @param string $slug
1081 *
1082 * @return string
1083 */
1084 function fs_esc_attr( $key, $slug ) {
1085 return esc_attr( fs_text( $key, $slug ) );
1086 }
1087 }
1088
1089 if ( ! function_exists( 'fs_esc_attr_inline' ) ) {
1090 /**
1091 * @author Vova Feldman (@svovaf)
1092 * @since 1.2.3
1093 *
1094 * @param string $text Translatable string.
1095 * @param string $key String key for overrides.
1096 * @param string $slug Module slug for overrides.
1097 *
1098 * @return string
1099 */
1100 function fs_esc_attr_inline( $text, $key = '', $slug = 'freemius' ) {
1101 return esc_attr( _fs_text_inline( $text, $key, $slug ) );
1102 }
1103 }
1104
1105 if ( ! function_exists( 'fs_esc_attr_x_inline' ) ) {
1106 /**
1107 * @author Vova Feldman (@svovaf)
1108 * @since 1.2.3
1109 *
1110 * @param string $text Translatable string.
1111 * @param string $context Context information for the translators.
1112 * @param string $key String key for overrides.
1113 * @param string $slug Module slug for overrides.
1114 *
1115 * @return string
1116 */
1117 function fs_esc_attr_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
1118 return esc_attr( _fs_text_x_inline( $text, $context, $key, $slug ) );
1119 }
1120 }
1121
1122 if ( ! function_exists( 'fs_esc_attr_echo' ) ) {
1123 /**
1124 * @author Vova Feldman
1125 * @since 1.2.1.6
1126 *
1127 * @param string $key
1128 * @param string $slug
1129 */
1130 function fs_esc_attr_echo( $key, $slug ) {
1131 echo esc_attr( fs_text( $key, $slug ) );
1132 }
1133 }
1134
1135 if ( ! function_exists( 'fs_esc_attr_echo_inline' ) ) {
1136 /**
1137 * @author Vova Feldman (@svovaf)
1138 * @since 1.2.3
1139 *
1140 * @param string $text Translatable string.
1141 * @param string $key String key for overrides.
1142 * @param string $slug Module slug for overrides.
1143 */
1144 function fs_esc_attr_echo_inline( $text, $key = '', $slug = 'freemius' ) {
1145 echo esc_attr( _fs_text_inline( $text, $key, $slug ) );
1146 }
1147 }
1148
1149 if ( ! function_exists( 'fs_esc_js' ) ) {
1150 /**
1151 * @author Vova Feldman
1152 * @since 1.2.1.6
1153 *
1154 * @param string $key
1155 * @param string $slug
1156 *
1157 * @return string
1158 */
1159 function fs_esc_js( $key, $slug ) {
1160 return esc_js( fs_text( $key, $slug ) );
1161 }
1162 }
1163
1164 if ( ! function_exists( 'fs_esc_js_inline' ) ) {
1165 /**
1166 * @author Vova Feldman (@svovaf)
1167 * @since 1.2.3
1168 *
1169 * @param string $text Translatable string.
1170 * @param string $key String key for overrides.
1171 * @param string $slug Module slug for overrides.
1172 *
1173 * @return string
1174 */
1175 function fs_esc_js_inline( $text, $key = '', $slug = 'freemius' ) {
1176 return esc_js( _fs_text_inline( $text, $key, $slug ) );
1177 }
1178 }
1179
1180 if ( ! function_exists( 'fs_esc_js_x_inline' ) ) {
1181 /**
1182 * @author Vova Feldman (@svovaf)
1183 * @since 1.2.3
1184 *
1185 * @param string $text Translatable string.
1186 * @param string $context Context information for the translators.
1187 * @param string $key String key for overrides.
1188 * @param string $slug Module slug for overrides.
1189 *
1190 * @return string
1191 */
1192 function fs_esc_js_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
1193 return esc_js( _fs_text_x_inline( $text, $context, $key, $slug ) );
1194 }
1195 }
1196
1197 if ( ! function_exists( 'fs_esc_js_echo_x_inline' ) ) {
1198 /**
1199 * @author Vova Feldman (@svovaf)
1200 * @since 1.2.3
1201 *
1202 * @param string $text Translatable string.
1203 * @param string $context Context information for the translators.
1204 * @param string $key String key for overrides.
1205 * @param string $slug Module slug for overrides.
1206 *
1207 * @return string
1208 */
1209 function fs_esc_js_echo_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
1210 echo esc_js( _fs_text_x_inline( $text, $context, $key, $slug ) );
1211 }
1212 }
1213
1214 if ( ! function_exists( 'fs_esc_js_echo' ) ) {
1215 /**
1216 * @author Vova Feldman
1217 * @since 1.2.1.6
1218 *
1219 * @param string $key
1220 * @param string $slug
1221 */
1222 function fs_esc_js_echo( $key, $slug ) {
1223 echo esc_js( fs_text( $key, $slug ) );
1224 }
1225 }
1226
1227 if ( ! function_exists( 'fs_esc_js_echo_inline' ) ) {
1228 /**
1229 * @author Vova Feldman (@svovaf)
1230 * @since 1.2.3
1231 *
1232 * @param string $text Translatable string.
1233 * @param string $key String key for overrides.
1234 * @param string $slug Module slug for overrides.
1235 */
1236 function fs_esc_js_echo_inline( $text, $key = '', $slug = 'freemius' ) {
1237 echo esc_js( _fs_text_inline( $text, $key, $slug ) );
1238 }
1239 }
1240
1241 if ( ! function_exists( 'fs_json_encode_echo' ) ) {
1242 /**
1243 * @author Vova Feldman
1244 * @since 1.2.1.6
1245 *
1246 * @param string $key
1247 * @param string $slug
1248 */
1249 function fs_json_encode_echo( $key, $slug ) {
1250 echo json_encode( fs_text( $key, $slug ) );
1251 }
1252 }
1253
1254 if ( ! function_exists( 'fs_json_encode_echo_inline' ) ) {
1255 /**
1256 * @author Vova Feldman (@svovaf)
1257 * @since 1.2.3
1258 *
1259 * @param string $text Translatable string.
1260 * @param string $key String key for overrides.
1261 * @param string $slug Module slug for overrides.
1262 */
1263 function fs_json_encode_echo_inline( $text, $key = '', $slug = 'freemius' ) {
1264 echo json_encode( _fs_text_inline( $text, $key, $slug ) );
1265 }
1266 }
1267
1268 if ( ! function_exists( 'fs_esc_html' ) ) {
1269 /**
1270 * @author Vova Feldman
1271 * @since 1.2.1.6
1272 *
1273 * @param string $key
1274 * @param string $slug
1275 *
1276 * @return string
1277 */
1278 function fs_esc_html( $key, $slug ) {
1279 return esc_html( fs_text( $key, $slug ) );
1280 }
1281 }
1282
1283 if ( ! function_exists( 'fs_esc_html_inline' ) ) {
1284 /**
1285 * @author Vova Feldman (@svovaf)
1286 * @since 1.2.3
1287 *
1288 * @param string $text Translatable string.
1289 * @param string $key String key for overrides.
1290 * @param string $slug Module slug for overrides.
1291 *
1292 * @return string
1293 */
1294 function fs_esc_html_inline( $text, $key = '', $slug = 'freemius' ) {
1295 return esc_html( _fs_text_inline( $text, $key, $slug ) );
1296 }
1297 }
1298
1299 if ( ! function_exists( 'fs_esc_html_x_inline' ) ) {
1300 /**
1301 * @author Vova Feldman (@svovaf)
1302 * @since 1.2.3
1303 *
1304 * @param string $text Translatable string.
1305 * @param string $context Context information for the translators.
1306 * @param string $key String key for overrides.
1307 * @param string $slug Module slug for overrides.
1308 *
1309 * @return string
1310 */
1311 function fs_esc_html_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
1312 return esc_html( _fs_text_x_inline( $text, $context, $key, $slug ) );
1313 }
1314 }
1315
1316 if ( ! function_exists( 'fs_esc_html_echo_x_inline' ) ) {
1317 /**
1318 * @author Vova Feldman (@svovaf)
1319 * @since 1.2.3
1320 *
1321 * @param string $text Translatable string.
1322 * @param string $context Context information for the translators.
1323 * @param string $key String key for overrides.
1324 * @param string $slug Module slug for overrides.
1325 */
1326 function fs_esc_html_echo_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
1327 echo esc_html( _fs_text_x_inline( $text, $context, $key, $slug ) );
1328 }
1329 }
1330
1331 if ( ! function_exists( 'fs_esc_html_echo' ) ) {
1332 /**
1333 * @author Vova Feldman
1334 * @since 1.2.1.6
1335 *
1336 * @param string $key
1337 * @param string $slug
1338 */
1339 function fs_esc_html_echo( $key, $slug ) {
1340 echo esc_html( fs_text( $key, $slug ) );
1341 }
1342 }
1343
1344 if ( ! function_exists( 'fs_esc_html_echo_inline' ) ) {
1345 /**
1346 * @author Vova Feldman (@svovaf)
1347 * @since 1.2.3
1348 *
1349 * @param string $text Translatable string.
1350 * @param string $key String key for overrides.
1351 * @param string $slug Module slug for overrides.
1352 */
1353 function fs_esc_html_echo_inline( $text, $key = '', $slug = 'freemius' ) {
1354 echo esc_html( _fs_text_inline( $text, $key, $slug ) );
1355 }
1356 }
1357
1358 if ( ! function_exists( 'fs_override_i18n' ) ) {
1359 /**
1360 * Override default i18n text phrases.
1361 *
1362 * @author Vova Feldman (@svovaf)
1363 * @since 1.1.6
1364 *
1365 * @param array[string]string $key_value
1366 * @param string $slug
1367 *
1368 * @global $fs_text_overrides
1369 */
1370 function fs_override_i18n( array $key_value, $slug = 'freemius' ) {
1371 global $fs_text_overrides;
1372
1373 if ( ! isset( $fs_text_overrides[ $slug ] ) ) {
1374 $fs_text_overrides[ $slug ] = array();
1375 }
1376
1377 foreach ( $key_value as $key => $value ) {
1378 $fs_text_overrides[ $slug ][ $key ] = $value;
1379 }
1380 }
1381 }
1382
1383 #endregion
1384
1385 #--------------------------------------------------------------------------------
1386 #region Multisite Network
1387 #--------------------------------------------------------------------------------
1388
1389 if ( ! function_exists( 'fs_is_plugin_uninstall' ) ) {
1390 /**
1391 * @author Vova Feldman (@svovaf)
1392 * @since 2.0.0
1393 */
1394 function fs_is_plugin_uninstall() {
1395 return (
1396 defined( 'WP_UNINSTALL_PLUGIN' ) ||
1397 ( 0 < did_action( 'pre_uninstall_plugin' ) )
1398 );
1399 }
1400 }
1401
1402 if ( ! function_exists( 'fs_is_network_admin' ) ) {
1403 /**
1404 * Unlike is_network_admin(), this one will also work properly when
1405 * the context execution is WP AJAX handler, and during plugin
1406 * uninstall.
1407 *
1408 * @author Vova Feldman (@svovaf)
1409 * @since 2.0.0
1410 */
1411 function fs_is_network_admin() {
1412 return (
1413 WP_FS__IS_NETWORK_ADMIN ||
1414 ( is_multisite() && fs_is_plugin_uninstall() )
1415 );
1416 }
1417 }
1418
1419 if ( ! function_exists( 'fs_is_blog_admin' ) ) {
1420 /**
1421 * Unlike is_blog_admin(), this one will also work properly when
1422 * the context execution is WP AJAX handler, and during plugin
1423 * uninstall.
1424 *
1425 * @author Vova Feldman (@svovaf)
1426 * @since 2.0.0
1427 */
1428 function fs_is_blog_admin() {
1429 return (
1430 WP_FS__IS_BLOG_ADMIN ||
1431 ( ! is_multisite() && fs_is_plugin_uninstall() )
1432 );
1433 }
1434 }
1435
1436 #endregion
1437
1438 if ( ! function_exists( 'fs_apply_filter' ) ) {
1439 /**
1440 * Apply filter for specific plugin.
1441 *
1442 * @author Vova Feldman (@svovaf)
1443 * @since 1.0.9
1444 *
1445 * @param string $module_unique_affix Module's unique affix.
1446 * @param string $tag The name of the filter hook.
1447 * @param mixed $value The value on which the filters hooked to `$tag` are applied on.
1448 *
1449 * @return mixed The filtered value after all hooked functions are applied to it.
1450 *
1451 * @uses apply_filters()
1452 */
1453 function fs_apply_filter( $module_unique_affix, $tag, $value ) {
1454 $args = func_get_args();
1455
1456 return call_user_func_array( 'apply_filters', array_merge(
1457 array( "fs_{$tag}_{$module_unique_affix}" ),
1458 array_slice( $args, 2 ) )
1459 );
1460 }
1461 }