has_expired() ) { wp_cache_delete( $key, $group ); $value = null; } else { self::$hit++; $hit = true; } } if ( self::$debug ) { $ratio = self::$hit / self::$count; Groups_Log::log( sprintf( 'Cache get [%4s] [%s|%s] [%6.2f%%]', $hit ? 'hit' : 'miss', json_encode( $key ), json_encode( $group ), $ratio * 100.0 ) ); } return $value; } /** * Retrieve an entry from cache, extended key. * * @since 4.0.0 * * @param string $key * @param string $group * * @return Groups_Cache_Object|NULL */ public static function get_ext( $key, $group = self::CACHE_GROUP ) { $key = self::extend_key( $key ); return self::get( $key, $group ); } /** * Retrieve an entry from cache, mutex read. * * @since 4.3.0 * * @param string $key * @param string $group * * @return Groups_Cache_Object|null returns a cache object on hit, null on cache miss */ public static function get_lock( $key, $group = self::CACHE_GROUP ) { $name = $key . '-' . $group; $lock = null; try { if ( isset( self::$locks[$name] ) ) { $lock = self::$locks[$name]; } else { $timeout = apply_filters( 'groups_cache_get_lock_timeout', self::LOCK_TIMEOUT, $key, $group ); if ( is_numeric( $timeout ) ) { $timeout = max( 0, intval( $timeout ) ); } else { $timeout = null; } $lock = new Groups_Lock( $name, $timeout ); } $lock->reader(); } catch ( Groups_Lock_Exception $lex ) { $lock = null; if ( self::$debug ) { Groups_Log::log( sprintf( 'Cache read lock fail [%s] [%s]', json_encode( $name ), $lex->getMessage() ) ); } } $result = self::get( $key, $group ); if ( $lock !== null ) { $lock->release(); self::$locks[$name] = $lock; } return $result; } /** * Store an entry in cache. * * @param string $key * @param string $value * @param string $group * @param int|null $expires default expiration applies if not provided * * @return boolean true if successful, otherwise false */ public static function set( $key, $value, $group = self::CACHE_GROUP, $expires = null ) { /** * Filter when cache entry expires. * * @since 4.0.0 * * @param int|null $expires * @param string $key * @param mixed $value * @param string $group * * @return int|null */ $expires = apply_filters( 'groups_cache_set_expires', $expires, $key, $value, $group ); if ( is_numeric( $expires ) ) { $expires = max( 0, intval( $expires ) ); } else { $expires = self::EXPIRES_DEFAULT; } $object = new Groups_Cache_Object( $key, $value, $expires ); if ( $expires === null || $expires === 0 ) { /** * Indefinite value. * * @since 4.0.0 * * @param int $value * * @return int */ $expires = apply_filters( 'groups_cache_set_expires_indefinite', PHP_INT_MAX ); $expires = is_numeric( $expires ) ? max( 0, intval( $expires ) ) : PHP_INT_MAX; } $set = wp_cache_set( $key, $object, $group, $expires ); if ( self::$debug ) { Groups_Log::log( sprintf( 'Cache set [%4s] [%s|%s]', $set ? 'ok' : 'fail', json_encode( $key ), json_encode( $group ) ) ); } return $set; } /** * Store an entry in cache, extended key. * * @param string $key * @param string $value * @param string $group * @param int|null $expires default expiration applies if not provided * * @return boolean true if successful, otherwise false */ public static function set_ext( $key, $value, $group = self::CACHE_GROUP, $expires = null ) { $key = self::extend_key( $key ); return self::set( $key, $value, $group, $expires ); } /** * Store an entry in cache, mutex write. * * @since 4.3.0 * * @param string $key * @param string $value * @param string $group * @param int|null $expires default expiration applies if not provided * * @return boolean true if successful, otherwise false */ public static function set_lock( $key, $value, $group = self::CACHE_GROUP, $expires = null ) { $name = $key . '-' . $group; $lock = null; try { if ( isset( self::$locks[$name] ) ) { $lock = self::$locks[$name]; } else { $timeout = apply_filters( 'groups_cache_set_lock_timeout', self::LOCK_TIMEOUT, $key, $group ); if ( is_numeric( $timeout ) ) { $timeout = max( 0, intval( $timeout ) ); } else { $timeout = null; } $lock = new Groups_Lock( $name, $timeout ); } $lock->writer(); } catch ( Groups_Lock_Exception $lex ) { $lock = null; if ( self::$debug ) { Groups_Log::log( sprintf( 'Cache write lock fail [%s] [%s]', json_encode( $name ), $lex->getMessage() ) ); } } $result = self::set( $key, $value, $group, $expires ); if ( $lock !== null ) { $lock->release(); self::$locks[$name] = $lock; } return $result; } /** * Delete a cache entry. * * @param string $key * @param string $group * * @return boolean true if successful, otherwise false */ public static function delete( $key, $group = self::CACHE_GROUP ) { $delete = wp_cache_delete( $key, $group ); if ( self::$debug ) { Groups_Log::log( sprintf( 'Cache del [%4s] [%s|%s]', $delete ? 'ok' : 'fail', json_encode( $key ), json_encode( $group ) ) ); } return $delete; } /** * Delete a cache entry, extended key. * * @param string $key * @param string $group * * @return boolean true if successful, otherwise false */ public static function delete_ext( $key, $group = self::CACHE_GROUP ) { $key = self::extend_key( $key ); return wp_cache_delete( $key, $group ); } /** * Delete a cache entry, mutex write. * * @param string $key * @param string $group * * @return boolean true if successful, otherwise false */ public static function delete_lock( $key, $group = self::CACHE_GROUP ) { $name = $key . '-' . $group; $lock = null; try { if ( isset( self::$locks[$name] ) ) { $lock = self::$locks[$name]; } else { $timeout = apply_filters( 'groups_cache_delete_lock_timeout', self::LOCK_TIMEOUT, $key, $group ); if ( is_numeric( $timeout ) ) { $timeout = max( 0, intval( $timeout ) ); } else { $timeout = null; } $lock = new Groups_Lock( $name, $timeout ); } $lock->writer(); } catch ( Groups_Lock_Exception $lex ) { $lock = null; if ( self::$debug ) { Groups_Log::log( sprintf( 'Cache delete lock fail [%s] [%s]', json_encode( $name ), $lex->getMessage() ) ); } } $result = self::delete( $key, $group ); if ( $lock !== null ) { $lock->release(); self::$locks[$name] = $lock; } return $result; } /** * Provide a specialized (groups-roles-user-based) version of the $group key. * * The $flags parameter is self::GROUPS_CACHE_GROUP | self::ROLES_CACHE_GROUP by default, * meaning a user's groups and roles are used to specialize the $group key. * * @since 2.20.0 * * @param string $group group key * @param int $flags determines what to take into account, null uses groups and roles by default * * @return string */ public static function get_group( $group, $flags = null ) { if ( $flags === null ) { $flags = self::GROUPS_CACHE_GROUP | self::ROLES_CACHE_GROUP; } $group_ids = array(); $roles = array(); $user_id = null; if ( function_exists( 'wp_get_current_user' ) ) { $user = wp_get_current_user(); if ( $user->exists() ) { if ( $flags & self::GROUPS_CACHE_GROUP ) { if ( is_array( $user->roles ) ) { $roles = $user->roles; sort( $roles ); } } if ( $flags & self::ROLES_CACHE_GROUP ) { if ( class_exists( '\Groups_User' ) ) { $groups_user = new \Groups_User( $user->ID ); $group_ids = $groups_user->get_group_ids_deep(); $group_ids = array_map( 'intval', $group_ids ); sort( $group_ids, SORT_NUMERIC ); } } if ( $flags & self::USER_CACHE_GROUP ) { $user_id = $user->ID; } } } if ( count( $roles ) > 0 ) { $group .= '_'; $group .= implode( '_', $roles ); } if ( count( $group_ids ) > 0 ) { $group .= '_'; $group .= implode( '_', $group_ids ); } if ( $user_id !== null ) { $group .= '_'; $group .= $user_id; } /** * Apply suffix to extended group. * * @param string $suffix * @param string $group * @param int $flags * * @return string */ $group_suffix = apply_filters( 'groups_cache_group_suffix', '', $group, $flags ); if ( !is_string( $group_suffix ) ) { $group_suffix = ''; } else { $group_suffix = trim( sanitize_key( $group_suffix ) ); } if ( strlen( $group_suffix ) > 0 ) { $group = $group . '_' . $group_suffix; } return $group; } /** * Provide a specialized (groups-roles-user-based) version of the $key. * * The $flags parameter is self::GROUPS_CACHE_GROUP | self::ROLES_CACHE_GROUP by default, * meaning a user's groups and roles are used to specialize the $key. * * @since 4.0.0 * * @param string $key group key * @param int $flags determines what to take into account, null uses groups and roles by default * * @return string */ public static function extend_key( $key, $flags = null ) { if ( $flags === null ) { $flags = self::GROUPS_CACHE_GROUP | self::ROLES_CACHE_GROUP; } $group_ids = array(); $roles = array(); $user_id = null; if ( function_exists( 'wp_get_current_user' ) ) { $user = wp_get_current_user(); if ( $user->exists() ) { if ( $flags & self::GROUPS_CACHE_GROUP ) { if ( is_array( $user->roles ) ) { $roles = $user->roles; sort( $roles ); } } if ( $flags & self::ROLES_CACHE_GROUP ) { if ( class_exists( '\Groups_User' ) ) { $groups_user = new \Groups_User( $user->ID ); $group_ids = $groups_user->get_group_ids_deep(); $group_ids = array_map( 'intval', $group_ids ); sort( $group_ids, SORT_NUMERIC ); } } if ( $flags & self::USER_CACHE_GROUP ) { $user_id = $user->ID; } } } if ( count( $roles ) > 0 ) { $key .= '_'; $key .= implode( '_', $roles ); } if ( count( $group_ids ) > 0 ) { $key .= '_'; $key .= implode( '_', $group_ids ); } if ( $user_id !== null ) { $key .= '_'; $key .= $user_id; } /** * Apply suffix to extended key. * * @param string $suffix * @param string $key * @param int $flags * * @return string */ $suffix = apply_filters( 'groups_cache_extend_key_suffix', '', $key, $flags ); if ( !is_string( $suffix ) ) { $suffix = ''; } else { $suffix = trim( sanitize_key( $suffix ) ); } if ( strlen( $suffix ) > 0 ) { $key = $key . '_' . $suffix; } return $key; } } Groups_Cache::init();