PluginProbe
Independent Analytics – WordPress Analytics Plugin / 2.11.2
Independent Analytics – WordPress Analytics Plugin v2.11.2
2.15.5 2.15.4 2.15.3 2.15.2 2.15.1 2.15.0 2.14.10 trunk 1.1 1.10 1.10.1 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.17.1 1.17.2 1.17.3 1.17.4 1.18 1.18.1 1.19.0 All 120 releases
independent-analytics / freemius / includes / fs-core-functions.php
fs-core-functions.php
1,506 lines 52.6 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 = true ) {
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_parse_url_params' ) ) {
592 /**
593 * Returns the query parameters of the given URL if there are any.
594 *
595 * @param string $url
596 * @param bool $html_entity_decode
597 *
598 * @return array<string, string> Key value pair where key represents the parameter name and value represents the parameter value.
599 */
600 function fs_parse_url_params( $url, $html_entity_decode = false ) {
601 $query_str = parse_url( $url, PHP_URL_QUERY );
602 $url_params = array();
603
604 if ( empty( $query_str ) ) {
605 return $url_params;
606 }
607
608 if ( $html_entity_decode ) {
609 $query_str = html_entity_decode( $query_str );
610 }
611
612 parse_str( $query_str, $url_params );
613
614 return $url_params;
615 }
616 }
617
618 if ( ! function_exists( 'fs_starts_with' ) ) {
619 /**
620 * Check if string starts with.
621 *
622 * @author Vova Feldman (@svovaf)
623 * @since 1.1.3
624 *
625 * @param string $haystack
626 * @param string $needle
627 *
628 * @return bool
629 */
630 function fs_starts_with( $haystack, $needle ) {
631 $length = strlen( $needle );
632
633 return ( substr( $haystack, 0, $length ) === $needle );
634 }
635 }
636
637 if ( ! function_exists( 'fs_ends_with' ) ) {
638 /**
639 * Check if string ends with.
640 *
641 * @author Vova Feldman (@svovaf)
642 * @since 2.0.0
643 *
644 * @param string $haystack
645 * @param string $needle
646 *
647 * @return bool
648 */
649 function fs_ends_with( $haystack, $needle ) {
650 $length = strlen( $needle );
651 $start = $length * - 1; // negative
652
653 return ( substr( $haystack, $start ) === $needle );
654 }
655 }
656
657 if ( ! function_exists( 'fs_strip_url_protocol' ) ) {
658 function fs_strip_url_protocol( $url ) {
659 if ( ! fs_starts_with( $url, 'http' ) ) {
660 return $url;
661 }
662
663 $protocol_pos = strpos( $url, '://' );
664
665 if ( $protocol_pos > 5 ) {
666 return $url;
667 }
668
669 return substr( $url, $protocol_pos + 3 );
670 }
671 }
672
673 #region Url Canonization ------------------------------------------------------------------
674
675 if ( ! function_exists( 'fs_canonize_url' ) ) {
676 /**
677 * @author Vova Feldman (@svovaf)
678 * @since 1.1.3
679 *
680 * @param string $url
681 * @param bool $omit_host
682 * @param array $ignore_params
683 *
684 * @return string
685 */
686 function fs_canonize_url( $url, $omit_host = false, $ignore_params = array() ) {
687 $parsed_url = parse_url( strtolower( $url ) );
688
689 // if ( ! isset( $parsed_url['host'] ) ) {
690 // return $url;
691 // }
692
693 $canonical = ( ( $omit_host || ! isset( $parsed_url['host'] ) ) ? '' : $parsed_url['host'] ) . $parsed_url['path'];
694
695 if ( isset( $parsed_url['query'] ) ) {
696 parse_str( $parsed_url['query'], $queryString );
697 $canonical .= '?' . fs_canonize_query_string( $queryString, $ignore_params );
698 }
699
700 return $canonical;
701 }
702 }
703
704 if ( ! function_exists( 'fs_canonize_query_string' ) ) {
705 /**
706 * @author Vova Feldman (@svovaf)
707 * @since 1.1.3
708 *
709 * @param array $params
710 * @param array $ignore_params
711 * @param bool $params_prefix
712 *
713 * @return string
714 */
715 function fs_canonize_query_string( array $params, array &$ignore_params, $params_prefix = false ) {
716 if ( ! is_array( $params ) || 0 === count( $params ) ) {
717 return '';
718 }
719
720 // Url encode both keys and values
721 $keys = fs_urlencode_rfc3986( array_keys( $params ) );
722 $values = fs_urlencode_rfc3986( array_values( $params ) );
723 $params = array_combine( $keys, $values );
724
725 // Parameters are sorted by name, using lexicographical byte value ordering.
726 // Ref: Spec: 9.1.1 (1)
727 uksort( $params, 'strcmp' );
728
729 $pairs = array();
730 foreach ( $params as $parameter => $value ) {
731 $lower_param = strtolower( $parameter );
732
733 // Skip ignore params.
734 if ( in_array( $lower_param, $ignore_params ) ||
735 ( false !== $params_prefix && fs_starts_with( $lower_param, $params_prefix ) )
736 ) {
737 continue;
738 }
739
740 if ( is_array( $value ) ) {
741 // If two or more parameters share the same name, they are sorted by their value
742 // Ref: Spec: 9.1.1 (1)
743 natsort( $value );
744 foreach ( $value as $duplicate_value ) {
745 $pairs[] = $lower_param . '=' . $duplicate_value;
746 }
747 } else {
748 $pairs[] = $lower_param . '=' . $value;
749 }
750 }
751
752 if ( 0 === count( $pairs ) ) {
753 return '';
754 }
755
756 return implode( "&", $pairs );
757 }
758 }
759
760 if ( ! function_exists( 'fs_urlencode_rfc3986' ) ) {
761 /**
762 * @author Vova Feldman (@svovaf)
763 * @since 1.1.3
764 *
765 * @param string|string[] $input
766 *
767 * @return array|mixed|string
768 */
769 function fs_urlencode_rfc3986( $input ) {
770 if ( is_array( $input ) ) {
771 return array_map( 'fs_urlencode_rfc3986', $input );
772 } else if ( is_scalar( $input ) ) {
773 return str_replace( '+', ' ', str_replace( '%7E', '~', rawurlencode( $input ) ) );
774 }
775
776 return '';
777 }
778 }
779
780 #endregion Url Canonization ------------------------------------------------------------------
781
782 if ( ! function_exists( 'fs_download_image' ) ) {
783 /**
784 * @author Vova Feldman (@svovaf)
785 *
786 * @since 1.2.2 Changed to usage of WP_Filesystem_Direct.
787 *
788 * @param string $from URL
789 * @param string $to File path.
790 *
791 * @return bool Is successfully downloaded.
792 */
793 function fs_download_image( $from, $to ) {
794 $dir = dirname( $to );
795
796 if ( 'direct' !== get_filesystem_method( array(), $dir ) ) {
797 return false;
798 }
799
800 if ( ! class_exists( 'WP_Filesystem_Direct' ) ) {
801 require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
802 require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php';
803 }
804
805 $fs = new WP_Filesystem_Direct( '' );
806 $tmpfile = download_url( $from );
807
808 if ( $tmpfile instanceof WP_Error ) {
809 // Issue downloading the file.
810 return false;
811 }
812
813 $fs->copy( $tmpfile, $to );
814 $fs->delete( $tmpfile );
815
816 return true;
817 }
818 }
819
820 /* General Utilities
821 --------------------------------------------------------------------------------------------*/
822
823 if ( ! function_exists( 'fs_sort_by_priority' ) ) {
824 /**
825 * Sorts an array by the value of the priority key.
826 *
827 * @author Daniel Iser (@danieliser)
828 * @since 1.1.7
829 *
830 * @param $a
831 * @param $b
832 *
833 * @return int
834 */
835 function fs_sort_by_priority( $a, $b ) {
836
837 // If b has a priority and a does not, b wins.
838 if ( ! isset( $a['priority'] ) && isset( $b['priority'] ) ) {
839 return 1;
840 } // If b has a priority and a does not, b wins.
841 elseif ( isset( $a['priority'] ) && ! isset( $b['priority'] ) ) {
842 return - 1;
843 } // If neither has a priority or both priorities are equal it's a tie.
844 elseif ( ( ! isset( $a['priority'] ) && ! isset( $b['priority'] ) ) || $a['priority'] === $b['priority'] ) {
845 return 0;
846 }
847
848 // If both have priority return the winner.
849 return ( $a['priority'] < $b['priority'] ) ? - 1 : 1;
850 }
851 }
852
853 #--------------------------------------------------------------------------------
854 #region Localization
855 #--------------------------------------------------------------------------------
856
857 global $fs_text_overrides;
858
859 if ( ! isset( $fs_text_overrides ) ) {
860 $fs_text_overrides = array();
861 }
862
863 if ( ! function_exists( 'fs_text' ) ) {
864 /**
865 * Retrieve a translated text by key.
866 *
867 * @author Vova Feldman (@svovaf)
868 * @since 1.2.1.7
869 *
870 * @param string $key
871 * @param string $slug
872 *
873 * @return string
874 *
875 * @global $fs_text_overrides
876 */
877 function fs_text( $key, $slug = 'freemius' ) {
878 global $fs_text_overrides;
879
880 if ( isset( $fs_text_overrides[ $slug ] ) ) {
881 if ( isset( $fs_text_overrides[ $slug ][ $key ] ) ) {
882 return $fs_text_overrides[ $slug ][ $key ];
883 }
884
885 $lower_key = strtolower( $key );
886 if ( isset( $fs_text_overrides[ $slug ][ $lower_key ] ) ) {
887 return $fs_text_overrides[ $slug ][ $lower_key ];
888 }
889 }
890
891 return $key;
892 }
893
894 #region Private
895
896 /**
897 * Retrieve an inline translated text by key with a context.
898 *
899 * @author Vova Feldman (@svovaf)
900 * @since 1.2.3
901 *
902 * @param string $text Translatable string.
903 * @param string $context Context information for the translators.
904 * @param string $key String key for overrides.
905 * @param string $slug Module slug for overrides.
906 *
907 * @return string
908 *
909 * @global $fs_text_overrides
910 */
911 function _fs_text_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
912 list( $text, $text_domain ) = fs_text_and_domain( $text, $key, $slug );
913
914 // Avoid misleading Theme Check warning.
915 $fn = 'translate_with_gettext_context';
916
917 return $fn( $text, $context, $text_domain );
918 }
919
920 #endregion
921
922 /**
923 * Retrieve an inline translated text by key with a context.
924 *
925 * @author Vova Feldman (@svovaf)
926 * @since 1.2.3
927 *
928 * @param string $text Translatable string.
929 * @param string $context Context information for the translators.
930 * @param string $key String key for overrides.
931 * @param string $slug Module slug for overrides.
932 *
933 * @return string
934 *
935 * @global $fs_text_overrides
936 */
937 function fs_text_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
938 return _fs_text_x_inline( $text, $context, $key, $slug );
939 }
940
941 /**
942 * Output a translated text by key.
943 *
944 * @author Vova Feldman (@svovaf)
945 * @since 1.2.1.7
946 *
947 * @param string $key
948 * @param string $slug
949 */
950 function fs_echo( $key, $slug = 'freemius' ) {
951 echo fs_text( $key, $slug );
952 }
953
954 /**
955 * Output an inline translated text.
956 *
957 * @author Vova Feldman (@svovaf)
958 * @since 1.2.3
959 *
960 * @param string $text Translatable string.
961 * @param string $key String key for overrides.
962 * @param string $slug Module slug for overrides.
963 */
964 function fs_echo_inline( $text, $key = '', $slug = 'freemius' ) {
965 echo _fs_text_inline( $text, $key, $slug );
966 }
967
968 /**
969 * Output an inline translated text with a context.
970 *
971 * @author Vova Feldman (@svovaf)
972 * @since 1.2.3
973 *
974 * @param string $text Translatable string.
975 * @param string $context Context information for the translators.
976 * @param string $key String key for overrides.
977 * @param string $slug Module slug for overrides.
978 */
979 function fs_echo_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
980 echo _fs_text_x_inline( $text, $context, $key, $slug );
981 }
982 }
983
984 if ( ! function_exists( 'fs_text_override' ) ) {
985 /**
986 * Get a translatable text override if exists, or `false`.
987 *
988 * @author Vova Feldman (@svovaf)
989 * @since 1.2.1.7
990 *
991 * @param string $text Translatable string.
992 * @param string $key String key for overrides.
993 * @param string $slug Module slug for overrides.
994 *
995 * @return string|false
996 */
997 function fs_text_override( $text, $key, $slug ) {
998 global $fs_text_overrides;
999
1000 /**
1001 * Check if string is overridden.
1002 */
1003 if ( ! isset( $fs_text_overrides[ $slug ] ) ) {
1004 return false;
1005 }
1006
1007 if ( empty( $key ) ) {
1008 $key = strtolower( str_replace( ' ', '-', $text ) );
1009 }
1010
1011 if ( isset( $fs_text_overrides[ $slug ][ $key ] ) ) {
1012 return $fs_text_overrides[ $slug ][ $key ];
1013 }
1014
1015 $lower_key = strtolower( $key );
1016 if ( isset( $fs_text_overrides[ $slug ][ $lower_key ] ) ) {
1017 return $fs_text_overrides[ $slug ][ $lower_key ];
1018 }
1019
1020 return false;
1021 }
1022 }
1023
1024 if ( ! function_exists( 'fs_text_and_domain' ) ) {
1025 /**
1026 * Get a translatable text and its text domain.
1027 *
1028 * 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.
1029 *
1030 * @author Vova Feldman (@svovaf)
1031 * @since 1.2.1.7
1032 *
1033 * @param string $text Translatable string.
1034 * @param string $key String key for overrides.
1035 * @param string $slug Module slug for overrides.
1036 *
1037 * @return string[]
1038 */
1039 function fs_text_and_domain( $text, $key, $slug ) {
1040 $override = fs_text_override( $text, $key, $slug );
1041
1042 if ( false === $override ) {
1043 // No override, use FS text domain.
1044 $text_domain = 'freemius';
1045 } else {
1046 // Found an override.
1047 $text = $override;
1048 // Use the module's text domain.
1049 $text_domain = $slug;
1050 }
1051
1052 return array( $text, $text_domain );
1053 }
1054 }
1055
1056 if ( ! function_exists( '_fs_text_inline' ) ) {
1057 /**
1058 * Retrieve an inline translated text by key.
1059 *
1060 * @author Vova Feldman (@svovaf)
1061 * @since 1.2.3
1062 *
1063 * @param string $text Translatable string.
1064 * @param string $key String key for overrides.
1065 * @param string $slug Module slug for overrides.
1066 *
1067 * @return string
1068 *
1069 * @global $fs_text_overrides
1070 */
1071 function _fs_text_inline( $text, $key = '', $slug = 'freemius' ) {
1072 list( $text, $text_domain ) = fs_text_and_domain( $text, $key, $slug );
1073
1074 // Avoid misleading Theme Check warning.
1075 $fn = 'translate';
1076
1077 return $fn( $text, $text_domain );
1078 }
1079 }
1080
1081 if ( ! function_exists( 'fs_text_inline' ) ) {
1082 /**
1083 * Retrieve an inline translated text by key.
1084 *
1085 * @author Vova Feldman (@svovaf)
1086 * @since 1.2.3
1087 *
1088 * @param string $text Translatable string.
1089 * @param string $key String key for overrides.
1090 * @param string $slug Module slug for overrides.
1091 *
1092 * @return string
1093 *
1094 * @global $fs_text_overrides
1095 */
1096 function fs_text_inline( $text, $key = '', $slug = 'freemius' ) {
1097 return _fs_text_inline( $text, $key, $slug );
1098 }
1099 }
1100
1101 if ( ! function_exists( 'fs_esc_attr' ) ) {
1102 /**
1103 * @author Vova Feldman
1104 * @since 1.2.1.6
1105 *
1106 * @param string $key
1107 * @param string $slug
1108 *
1109 * @return string
1110 */
1111 function fs_esc_attr( $key, $slug ) {
1112 return esc_attr( fs_text( $key, $slug ) );
1113 }
1114 }
1115
1116 if ( ! function_exists( 'fs_esc_attr_inline' ) ) {
1117 /**
1118 * @author Vova Feldman (@svovaf)
1119 * @since 1.2.3
1120 *
1121 * @param string $text Translatable string.
1122 * @param string $key String key for overrides.
1123 * @param string $slug Module slug for overrides.
1124 *
1125 * @return string
1126 */
1127 function fs_esc_attr_inline( $text, $key = '', $slug = 'freemius' ) {
1128 return esc_attr( _fs_text_inline( $text, $key, $slug ) );
1129 }
1130 }
1131
1132 if ( ! function_exists( 'fs_esc_attr_x_inline' ) ) {
1133 /**
1134 * @author Vova Feldman (@svovaf)
1135 * @since 1.2.3
1136 *
1137 * @param string $text Translatable string.
1138 * @param string $context Context information for the translators.
1139 * @param string $key String key for overrides.
1140 * @param string $slug Module slug for overrides.
1141 *
1142 * @return string
1143 */
1144 function fs_esc_attr_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
1145 return esc_attr( _fs_text_x_inline( $text, $context, $key, $slug ) );
1146 }
1147 }
1148
1149 if ( ! function_exists( 'fs_esc_attr_echo' ) ) {
1150 /**
1151 * @author Vova Feldman
1152 * @since 1.2.1.6
1153 *
1154 * @param string $key
1155 * @param string $slug
1156 */
1157 function fs_esc_attr_echo( $key, $slug ) {
1158 echo esc_attr( fs_text( $key, $slug ) );
1159 }
1160 }
1161
1162 if ( ! function_exists( 'fs_esc_attr_echo_inline' ) ) {
1163 /**
1164 * @author Vova Feldman (@svovaf)
1165 * @since 1.2.3
1166 *
1167 * @param string $text Translatable string.
1168 * @param string $key String key for overrides.
1169 * @param string $slug Module slug for overrides.
1170 */
1171 function fs_esc_attr_echo_inline( $text, $key = '', $slug = 'freemius' ) {
1172 echo esc_attr( _fs_text_inline( $text, $key, $slug ) );
1173 }
1174 }
1175
1176 if ( ! function_exists( 'fs_esc_js' ) ) {
1177 /**
1178 * @author Vova Feldman
1179 * @since 1.2.1.6
1180 *
1181 * @param string $key
1182 * @param string $slug
1183 *
1184 * @return string
1185 */
1186 function fs_esc_js( $key, $slug ) {
1187 return esc_js( fs_text( $key, $slug ) );
1188 }
1189 }
1190
1191 if ( ! function_exists( 'fs_esc_js_inline' ) ) {
1192 /**
1193 * @author Vova Feldman (@svovaf)
1194 * @since 1.2.3
1195 *
1196 * @param string $text Translatable string.
1197 * @param string $key String key for overrides.
1198 * @param string $slug Module slug for overrides.
1199 *
1200 * @return string
1201 */
1202 function fs_esc_js_inline( $text, $key = '', $slug = 'freemius' ) {
1203 return esc_js( _fs_text_inline( $text, $key, $slug ) );
1204 }
1205 }
1206
1207 if ( ! function_exists( 'fs_esc_js_x_inline' ) ) {
1208 /**
1209 * @author Vova Feldman (@svovaf)
1210 * @since 1.2.3
1211 *
1212 * @param string $text Translatable string.
1213 * @param string $context Context information for the translators.
1214 * @param string $key String key for overrides.
1215 * @param string $slug Module slug for overrides.
1216 *
1217 * @return string
1218 */
1219 function fs_esc_js_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
1220 return esc_js( _fs_text_x_inline( $text, $context, $key, $slug ) );
1221 }
1222 }
1223
1224 if ( ! function_exists( 'fs_esc_js_echo_x_inline' ) ) {
1225 /**
1226 * @author Vova Feldman (@svovaf)
1227 * @since 1.2.3
1228 *
1229 * @param string $text Translatable string.
1230 * @param string $context Context information for the translators.
1231 * @param string $key String key for overrides.
1232 * @param string $slug Module slug for overrides.
1233 *
1234 * @return void
1235 */
1236 function fs_esc_js_echo_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
1237 echo esc_js( _fs_text_x_inline( $text, $context, $key, $slug ) );
1238 }
1239 }
1240
1241 if ( ! function_exists( 'fs_esc_js_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_esc_js_echo( $key, $slug ) {
1250 echo esc_js( fs_text( $key, $slug ) );
1251 }
1252 }
1253
1254 if ( ! function_exists( 'fs_esc_js_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_esc_js_echo_inline( $text, $key = '', $slug = 'freemius' ) {
1264 echo esc_js( _fs_text_inline( $text, $key, $slug ) );
1265 }
1266 }
1267
1268 if ( ! function_exists( 'fs_json_encode_echo' ) ) {
1269 /**
1270 * @author Vova Feldman
1271 * @since 1.2.1.6
1272 *
1273 * @param string $key
1274 * @param string $slug
1275 */
1276 function fs_json_encode_echo( $key, $slug ) {
1277 echo json_encode( fs_text( $key, $slug ) );
1278 }
1279 }
1280
1281 if ( ! function_exists( 'fs_json_encode_echo_inline' ) ) {
1282 /**
1283 * @author Vova Feldman (@svovaf)
1284 * @since 1.2.3
1285 *
1286 * @param string $text Translatable string.
1287 * @param string $key String key for overrides.
1288 * @param string $slug Module slug for overrides.
1289 */
1290 function fs_json_encode_echo_inline( $text, $key = '', $slug = 'freemius' ) {
1291 echo json_encode( _fs_text_inline( $text, $key, $slug ) );
1292 }
1293 }
1294
1295 if ( ! function_exists( 'fs_esc_html' ) ) {
1296 /**
1297 * @author Vova Feldman
1298 * @since 1.2.1.6
1299 *
1300 * @param string $key
1301 * @param string $slug
1302 *
1303 * @return string
1304 */
1305 function fs_esc_html( $key, $slug ) {
1306 return esc_html( fs_text( $key, $slug ) );
1307 }
1308 }
1309
1310 if ( ! function_exists( 'fs_esc_html_inline' ) ) {
1311 /**
1312 * @author Vova Feldman (@svovaf)
1313 * @since 1.2.3
1314 *
1315 * @param string $text Translatable string.
1316 * @param string $key String key for overrides.
1317 * @param string $slug Module slug for overrides.
1318 *
1319 * @return string
1320 */
1321 function fs_esc_html_inline( $text, $key = '', $slug = 'freemius' ) {
1322 return esc_html( _fs_text_inline( $text, $key, $slug ) );
1323 }
1324 }
1325
1326 if ( ! function_exists( 'fs_esc_html_x_inline' ) ) {
1327 /**
1328 * @author Vova Feldman (@svovaf)
1329 * @since 1.2.3
1330 *
1331 * @param string $text Translatable string.
1332 * @param string $context Context information for the translators.
1333 * @param string $key String key for overrides.
1334 * @param string $slug Module slug for overrides.
1335 *
1336 * @return string
1337 */
1338 function fs_esc_html_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
1339 return esc_html( _fs_text_x_inline( $text, $context, $key, $slug ) );
1340 }
1341 }
1342
1343 if ( ! function_exists( 'fs_esc_html_echo_x_inline' ) ) {
1344 /**
1345 * @author Vova Feldman (@svovaf)
1346 * @since 1.2.3
1347 *
1348 * @param string $text Translatable string.
1349 * @param string $context Context information for the translators.
1350 * @param string $key String key for overrides.
1351 * @param string $slug Module slug for overrides.
1352 */
1353 function fs_esc_html_echo_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
1354 echo esc_html( _fs_text_x_inline( $text, $context, $key, $slug ) );
1355 }
1356 }
1357
1358 if ( ! function_exists( 'fs_esc_html_echo' ) ) {
1359 /**
1360 * @author Vova Feldman
1361 * @since 1.2.1.6
1362 *
1363 * @param string $key
1364 * @param string $slug
1365 */
1366 function fs_esc_html_echo( $key, $slug ) {
1367 echo esc_html( fs_text( $key, $slug ) );
1368 }
1369 }
1370
1371 if ( ! function_exists( 'fs_esc_html_echo_inline' ) ) {
1372 /**
1373 * @author Vova Feldman (@svovaf)
1374 * @since 1.2.3
1375 *
1376 * @param string $text Translatable string.
1377 * @param string $key String key for overrides.
1378 * @param string $slug Module slug for overrides.
1379 */
1380 function fs_esc_html_echo_inline( $text, $key = '', $slug = 'freemius' ) {
1381 echo esc_html( _fs_text_inline( $text, $key, $slug ) );
1382 }
1383 }
1384
1385 if ( ! function_exists( 'fs_override_i18n' ) ) {
1386 /**
1387 * Override default i18n text phrases.
1388 *
1389 * @author Vova Feldman (@svovaf)
1390 * @since 1.1.6
1391 *
1392 * @param array[string]string $key_value
1393 * @param string $slug
1394 *
1395 * @global $fs_text_overrides
1396 */
1397 function fs_override_i18n( array $key_value, $slug = 'freemius' ) {
1398 global $fs_text_overrides;
1399
1400 if ( ! isset( $fs_text_overrides[ $slug ] ) ) {
1401 $fs_text_overrides[ $slug ] = array();
1402 }
1403
1404 foreach ( $key_value as $key => $value ) {
1405 $fs_text_overrides[ $slug ][ $key ] = $value;
1406 }
1407 }
1408 }
1409
1410 #endregion
1411
1412 #--------------------------------------------------------------------------------
1413 #region Multisite Network
1414 #--------------------------------------------------------------------------------
1415
1416 if ( ! function_exists( 'fs_is_plugin_uninstall' ) ) {
1417 /**
1418 * @author Vova Feldman (@svovaf)
1419 * @since 2.0.0
1420 */
1421 function fs_is_plugin_uninstall() {
1422 return (
1423 defined( 'WP_UNINSTALL_PLUGIN' ) ||
1424 ( 0 < did_action( 'pre_uninstall_plugin' ) )
1425 );
1426 }
1427 }
1428
1429 if ( ! function_exists( 'fs_is_network_admin' ) ) {
1430 /**
1431 * Unlike is_network_admin(), this one will also work properly when
1432 * the context execution is WP AJAX handler, and during plugin
1433 * uninstall.
1434 *
1435 * @author Vova Feldman (@svovaf)
1436 * @since 2.0.0
1437 */
1438 function fs_is_network_admin() {
1439 return (
1440 WP_FS__IS_NETWORK_ADMIN ||
1441 ( is_multisite() && fs_is_plugin_uninstall() )
1442 );
1443 }
1444 }
1445
1446 if ( ! function_exists( 'fs_is_blog_admin' ) ) {
1447 /**
1448 * Unlike is_blog_admin(), this one will also work properly when
1449 * the context execution is WP AJAX handler, and during plugin
1450 * uninstall.
1451 *
1452 * @author Vova Feldman (@svovaf)
1453 * @since 2.0.0
1454 */
1455 function fs_is_blog_admin() {
1456 return (
1457 WP_FS__IS_BLOG_ADMIN ||
1458 ( ! is_multisite() && fs_is_plugin_uninstall() )
1459 );
1460 }
1461 }
1462
1463 #endregion
1464
1465 if ( ! function_exists( 'fs_apply_filter' ) ) {
1466 /**
1467 * Apply filter for specific plugin.
1468 *
1469 * @author Vova Feldman (@svovaf)
1470 * @since 1.0.9
1471 *
1472 * @param string $module_unique_affix Module's unique affix.
1473 * @param string $tag The name of the filter hook.
1474 * @param mixed $value The value on which the filters hooked to `$tag` are applied on.
1475 *
1476 * @return mixed The filtered value after all hooked functions are applied to it.
1477 *
1478 * @uses apply_filters()
1479 */
1480 function fs_apply_filter( $module_unique_affix, $tag, $value ) {
1481 $args = func_get_args();
1482
1483 return call_user_func_array( 'apply_filters', array_merge(
1484 array( "fs_{$tag}_{$module_unique_affix}" ),
1485 array_slice( $args, 2 ) )
1486 );
1487 }
1488 }
1489
1490 if ( ! function_exists( 'fs_get_optional_constant' ) ) {
1491 /**
1492 * Gets the value of an optional constant. If the constant is not defined, the default value will be returned.
1493 *
1494 * @author Swashata Ghosh (@swashata)
1495 * @since 2.5.12.5
1496 *
1497 * @param string $constant_name
1498 * @param mixed $default_value
1499 *
1500 * @return mixed
1501 */
1502 function fs_get_optional_constant( $constant_name, $default_value = null ) {
1503 return defined( $constant_name ) ? constant( $constant_name ) : $default_value;
1504 }
1505 }
1506