| 1 |
<?php |
| 2 |
/** |
| 3 |
* Compatibility functions. |
| 4 |
* |
| 5 |
* @package ContentControl |
| 6 |
*/ |
| 7 |
|
| 8 |
namespace ContentControl; |
| 9 |
|
| 10 |
use function ContentControl\get_query; |
| 11 |
|
| 12 |
defined( 'ABSPATH' ) || exit; |
| 13 |
|
| 14 |
/** |
| 15 |
* Checks whether function is disabled. |
| 16 |
* |
| 17 |
* @param string $func Name of the function. |
| 18 |
* |
| 19 |
* @return bool Whether or not function is disabled. |
| 20 |
*/ |
| 21 |
function is_func_disabled( $func ) { |
| 22 |
$disabled_functions = ini_get( 'disable_functions' ); |
| 23 |
|
| 24 |
$disabled = $disabled_functions ? explode( ',', $disabled_functions ) : []; |
| 25 |
|
| 26 |
return in_array( $func, $disabled, true ); |
| 27 |
} |
| 28 |
|
| 29 |
/** |
| 30 |
* Checks if the current request is a WP REST API request. |
| 31 |
* |
| 32 |
* Case #1: After WP_REST_Request initialisation |
| 33 |
* Case #2: Support "plain" permalink settings and check if `rest_route` starts with `/` |
| 34 |
* Case #3: It can happen that WP_Rewrite is not yet initialized, |
| 35 |
* so do this (wp-settings.php) |
| 36 |
* Case #4: URL Path begins with wp-json/ (your REST prefix) |
| 37 |
* Also supports WP installations in subfolders |
| 38 |
* |
| 39 |
* @returns boolean |
| 40 |
* @author matzeeable |
| 41 |
* |
| 42 |
* @return bool |
| 43 |
*/ |
| 44 |
function is_rest() { |
| 45 |
static $is_rest; |
| 46 |
|
| 47 |
if ( isset( $is_rest ) ) { |
| 48 |
return $is_rest; |
| 49 |
} |
| 50 |
|
| 51 |
// Callback to avoid duplicative $is_rest assignments, only runs once. |
| 52 |
$is_rest = ( function () { |
| 53 |
// phpcs:disable WordPress.Security.NonceVerification.Recommended |
| 54 |
if ( ( defined( 'REST_REQUEST' ) && REST_REQUEST )// (#1) |
| 55 |
|| ( isset( $_GET['rest_route'] ) && is_string( $_GET['rest_route'] ) // (#2) |
| 56 |
&& strpos( sanitize_text_field( wp_unslash( $_GET['rest_route'] ) ), '/', 0 ) === 0 ) ) { |
| 57 |
return true; |
| 58 |
} |
| 59 |
|
| 60 |
// (#4) |
| 61 |
$rest_url = wp_parse_url( trailingslashit( rest_url() ) ); |
| 62 |
$current_url = wp_parse_url( add_query_arg( [] ) ); |
| 63 |
|
| 64 |
if ( ! $rest_url || ! $current_url ) { |
| 65 |
return false; |
| 66 |
} |
| 67 |
|
| 68 |
$current_path = isset( $current_url['path'] ) ? $current_url['path'] : false; |
| 69 |
$rest_path = isset( $rest_url['path'] ) ? $rest_url['path'] : false; |
| 70 |
|
| 71 |
// If one of the URLs failed to parse, then the current request isn't a REST request. |
| 72 |
if ( ! $current_path || ! $rest_path ) { |
| 73 |
return false; |
| 74 |
} |
| 75 |
|
| 76 |
return strpos( $current_path, $rest_path, 0 ) === 0; |
| 77 |
// phpcs:enable WordPress.Security.NonceVerification.Recommended |
| 78 |
} )(); |
| 79 |
|
| 80 |
return $is_rest; |
| 81 |
} |
| 82 |
|
| 83 |
/** |
| 84 |
* Check if this is a core WP REST namespace. |
| 85 |
* |
| 86 |
* @return boolean |
| 87 |
* |
| 88 |
* @since 2.2.0 |
| 89 |
*/ |
| 90 |
function is_wp_core_rest_namespace() { |
| 91 |
if ( ! is_rest() ) { |
| 92 |
return false; |
| 93 |
} |
| 94 |
|
| 95 |
global $wp; |
| 96 |
|
| 97 |
$rest_route = isset( $wp->query_vars['rest_route'] ) ? $wp->query_vars['rest_route'] : ''; |
| 98 |
|
| 99 |
// Check if this is core WP REST namespace. |
| 100 |
return strpos( $rest_route, '/wp/v2' ) === 0; |
| 101 |
} |
| 102 |
|
| 103 |
/** |
| 104 |
* Check if this is a cron request. |
| 105 |
* |
| 106 |
* @return boolean |
| 107 |
*/ |
| 108 |
function is_cron() { |
| 109 |
return defined( 'DOING_CRON' ) && DOING_CRON; |
| 110 |
} |
| 111 |
|
| 112 |
/** |
| 113 |
* Check if this is an AJAX request. |
| 114 |
* |
| 115 |
* @return boolean |
| 116 |
*/ |
| 117 |
function is_ajax() { |
| 118 |
return defined( 'DOING_AJAX' ) && DOING_AJAX; |
| 119 |
} |
| 120 |
|
| 121 |
/** |
| 122 |
* Check if this is a frontend request. |
| 123 |
* |
| 124 |
* @return boolean |
| 125 |
*/ |
| 126 |
function is_frontend() { |
| 127 |
// Cached. |
| 128 |
static $is_frontend; |
| 129 |
|
| 130 |
// phpcs:ignore |
| 131 |
if ( isset( $is_frontend ) ) { |
| 132 |
// Not fully tested, but if we have a cached value, we can return it. |
| 133 |
// return $is_frontend;. |
| 134 |
$temp = $is_frontend; |
| 135 |
} |
| 136 |
|
| 137 |
$query = get_query(); |
| 138 |
|
| 139 |
$wp_query = $query instanceof \WP_Query ? $query : null; |
| 140 |
|
| 141 |
$request_uri = isset( $_SERVER['REQUEST_URI'] ) && is_string( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : ''; |
| 142 |
|
| 143 |
if ( |
| 144 |
// Check if is CLI. |
| 145 |
( defined( 'WP_CLI' ) && WP_CLI ) || |
| 146 |
// Check if is REST. |
| 147 |
is_admin() || |
| 148 |
is_ajax() || |
| 149 |
is_cron() || |
| 150 |
( $wp_query && $wp_query->is_admin ) || |
| 151 |
( $wp_query && $wp_query->is_favicon() ) || |
| 152 |
( $wp_query && $wp_query->is_robots() ) || |
| 153 |
strpos( $request_uri, 'favicon.ico' ) !== false || |
| 154 |
strpos( $request_uri, 'robots.txt' ) !== false |
| 155 |
) { |
| 156 |
$is_frontend = false; |
| 157 |
} else { |
| 158 |
$is_frontend = true; |
| 159 |
} |
| 160 |
|
| 161 |
return $is_frontend; |
| 162 |
} |
| 163 |
|
| 164 |
/** |
| 165 |
* Change camelCase to snake_case. |
| 166 |
* |
| 167 |
* @param string $str String to convert. |
| 168 |
* |
| 169 |
* @return string Converted string. |
| 170 |
*/ |
| 171 |
function camel_case_to_snake_case( $str ) { |
| 172 |
return strtolower( preg_replace( '/(?<!^)[A-Z]/', '_$0', $str ) ); |
| 173 |
} |
| 174 |
|
| 175 |
/** |
| 176 |
* Change snake_case to camelCase. |
| 177 |
* |
| 178 |
* @param string $str String to convert. |
| 179 |
* |
| 180 |
* @return string Converted string. |
| 181 |
*/ |
| 182 |
function snake_case_to_camel_case( $str ) { |
| 183 |
return lcfirst( str_replace( '_', '', ucwords( $str, '_' ) ) ); |
| 184 |
} |
| 185 |
|
| 186 |
/** |
| 187 |
* Get array values using dot.notation. |
| 188 |
* |
| 189 |
* @param string $key Key to fetch. |
| 190 |
* @param array<string,mixed> $data Array to fetch from. |
| 191 |
* @param string|null $key_case Case to use for key (snake_case|camelCase). |
| 192 |
* |
| 193 |
* @return mixed|null |
| 194 |
*/ |
| 195 |
function fetch_key_from_array( $key, $data, $key_case = null ) { |
| 196 |
// If key is .notation, then we need to traverse the array. |
| 197 |
$dotted_keys = explode( '.', $key ); |
| 198 |
|
| 199 |
foreach ( $dotted_keys as $key ) { |
| 200 |
if ( $key_case ) { |
| 201 |
switch ( $key_case ) { |
| 202 |
case 'snake_case': |
| 203 |
// Check if key is camelCase & convert to snake_case. |
| 204 |
$key = camel_case_to_snake_case( $key ); |
| 205 |
break; |
| 206 |
case 'camelCase': |
| 207 |
// Check if key is snake_case & convert to camelCase. |
| 208 |
$key = snake_case_to_camel_case( $key ); |
| 209 |
break; |
| 210 |
} |
| 211 |
} |
| 212 |
|
| 213 |
if ( ! isset( $data[ $key ] ) ) { |
| 214 |
return null; |
| 215 |
} |
| 216 |
|
| 217 |
$data = $data[ $key ]; |
| 218 |
} |
| 219 |
|
| 220 |
return $data ? $data : null; |
| 221 |
} |
| 222 |
|
| 223 |
/** |
| 224 |
* Convert hex to rgba. |
| 225 |
* |
| 226 |
* @param string $hex_code Hex code to convert. |
| 227 |
* @param float $opacity Opacity to use. |
| 228 |
* |
| 229 |
* @return string Converted rgba string. |
| 230 |
*/ |
| 231 |
function convert_hex_to_rgba( $hex_code, $opacity = 1 ) { |
| 232 |
$hex = str_replace( '#', '', $hex_code ); |
| 233 |
|
| 234 |
if ( strlen( $hex ) === 3 ) { |
| 235 |
$hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2]; |
| 236 |
} |
| 237 |
|
| 238 |
$r = hexdec( substr( $hex, 0, 2 ) ); |
| 239 |
$g = hexdec( substr( $hex, 2, 2 ) ); |
| 240 |
$b = hexdec( substr( $hex, 4, 2 ) ); |
| 241 |
|
| 242 |
/* Backward compatibility for whole number based opacity values. */ |
| 243 |
if ( $opacity > 1 && $opacity <= 100 ) { |
| 244 |
$opacity = $opacity / 100; |
| 245 |
} |
| 246 |
|
| 247 |
return "rgba($r,$g,$b,$opacity)"; |
| 248 |
} |
| 249 |
|
| 250 |
/** |
| 251 |
* Function that deeply cleans arrays for wp_maybe_serialize |
| 252 |
* |
| 253 |
* Gets rid of Closure and other invalid data types. |
| 254 |
* |
| 255 |
* @param array<mixed> $arr Array to clean. |
| 256 |
* |
| 257 |
* @return array<mixed> Cleaned array. |
| 258 |
*/ |
| 259 |
function deep_clean_array( $arr ) { |
| 260 |
// Clean \Closure values deeply. |
| 261 |
array_walk_recursive( |
| 262 |
$arr, |
| 263 |
function ( &$value ) { |
| 264 |
if ( $value instanceof \Closure ) { |
| 265 |
$value = null; |
| 266 |
} |
| 267 |
} |
| 268 |
); |
| 269 |
|
| 270 |
return $arr; |
| 271 |
} |
| 272 |
|