rules = $rules; $this->locales = $locales; } public function resolve( $base_value, $variable, $context ) { if ( empty( $variable['id'] ) || ( isset( $variable['scope'] ) && 'site' !== $variable['scope'] ) ) { return $base_value; } foreach ( $this->rules->for_variable( $variable['id'], true ) as $rule ) { if ( $this->matches( $rule['conditions'], $context ) ) { return apply_filters( 'glovario_rule_alternative_value', $rule['alternative_value'], $rule, $variable, $context ); } } return $base_value; } public function matches( $conditions, $context ) { $conditions = wp_parse_args( is_array( $conditions ) ? $conditions : array(), array( 'version' => 1, 'date' => array(), 'auth' => 'everyone', 'roles' => array(), 'post_types' => array(), 'post_ids' => array(), 'locales' => array(), ) ); if ( self::has_audience_conditions( $conditions ) && ! apply_filters( 'glovario_rule_audience_conditions_supported', false ) ) { return false; } $date = is_array( $conditions['date'] ) ? $conditions['date'] : array(); $now = isset( $context['timestamp'] ) ? (int) $context['timestamp'] : time(); // An unreadable date (only possible through corrupted data) never matches. $from = empty( $date['from'] ) ? null : self::site_timestamp( $date['from'] ); $until = empty( $date['until'] ) ? null : self::site_timestamp( $date['until'] ); if ( ! empty( $date['from'] ) && ( null === $from || $now < $from ) ) { return false; } if ( ! empty( $date['until'] ) && ( null === $until || $now > $until ) ) { return false; } if ( ! empty( $conditions['locales'] ) ) { $locale = sanitize_locale_name( (string) apply_filters( 'glovario_current_locale', $context['locale'] ?? determine_locale(), $context ) ); $rule_locales = array_values( (array) $conditions['locales'] ); /** * Short-circuits language matching. * * @param bool|null $matches Null to use the two-language matching below. * @param array $rule_locales Locales stored on the rule. * @param string $locale Locale of the current request. * @param array $context Resolution context. */ $matches = apply_filters( 'glovario_rule_locale_match', null, $rule_locales, $locale, $context ); if ( ! ( null === $matches ? $this->matches_language( $rule_locales, $locale ) : $matches ) ) { return false; } } return (bool) apply_filters( 'glovario_rule_conditions_match', true, $conditions, $context ); } /** * A language rule applies when it names one language, that language is the * default or the second language, and it is the language of the request. * Rules for several languages, or for other languages, are kept but ignored. * * @param array $rule_locales Locales stored on the rule. * @param string $locale Locale of the current request. * @return bool */ private function matches_language( $rule_locales, $locale ) { if ( 1 !== count( $rule_locales ) || sanitize_locale_name( (string) $rule_locales[0] ) !== $locale ) { return false; } if ( ! $this->locales ) { return true; } $settings = $this->locales->settings(); return $locale === $settings['default_locale'] || ( '' !== $settings['second_locale'] && $locale === $settings['second_locale'] ); } /** * Whether a rule uses audience or content conditions. * * @param array $conditions Rule conditions. * @return bool */ public static function has_audience_conditions( $conditions ) { $auth = $conditions['auth'] ?? 'everyone'; return ( '' !== $auth && 'everyone' !== $auth ) || ! empty( $conditions['roles'] ) || ! empty( $conditions['post_types'] ) || ! empty( $conditions['post_ids'] ); } /** * Convert a rule date (site timezone) to a Unix timestamp. * * @param string $value Date such as 2026-12-24T00:00. * @return int|null Null when the date cannot be read. */ public static function site_timestamp( $value ) { try { $date = new \DateTimeImmutable( (string) $value, wp_timezone() ); return $date->getTimestamp(); } catch ( \Exception $exception ) { return null; } } }