$step Step. * @return array> */ public static function get_step_conditions( array $step ): array { if ( isset( $step['condition'] ) && is_array( $step['condition'] ) && ! empty( $step['condition'] ) ) { return array( $step['condition'] ); } if ( isset( $step['conditions'] ) && is_array( $step['conditions'] ) ) { return $step['conditions']; } $variable = trim( (string) ( $step['variable'] ?? '' ) ); $operator = trim( (string) ( $step['operator'] ?? '' ) ); $value = trim( (string) ( $step['value'] ?? '' ) ); if ( '' !== $variable && '' !== $operator && '' !== $value ) { return array( array( 'field' => $variable, 'variable' => $variable, 'operator' => $operator, 'value' => $value, ), ); } return array(); } /** * Evaluate every condition with AND semantics. * * @param array $context Execution context. * @param array> $conditions Conditions. * @return bool */ public static function evaluate_conditions( array $context, array $conditions ): bool { if ( empty( $conditions ) ) { return true; } foreach ( $conditions as $condition ) { if ( ! is_array( $condition ) ) { continue; } if ( ! self::evaluate_one( $condition, $context ) ) { return false; } } return true; } /** * Human-readable condition description for logs. * * @param array $condition Condition. * @param array $context Context (unused, kept for Python parity). * @return array */ public static function describe_condition( array $condition, array $context = array() ): array { $field = self::field_name( $condition ); $operator = trim( (string) ( $condition['operator'] ?? '' ) ); $value = $condition['value'] ?? ''; $labels = Conditions::getOperators(); return array( 'field' => $field, 'operator' => $operator, 'operator_label' => $labels[ $operator ] ?? $operator, 'value' => $value, 'actual' => self::resolve_field_value( $field, $context ), ); } /** * Evaluate a single condition. * * @param array $condition Condition. * @param array $context Context. * @return bool */ private static function evaluate_one( array $condition, array $context ): bool { $normalized = array( 'variable' => self::field_name( $condition ), 'operator' => trim( (string) ( $condition['operator'] ?? '' ) ), 'value' => is_scalar( $condition['value'] ?? '' ) ? trim( (string) $condition['value'] ) : wp_json_encode( $condition['value'] ), ); if ( '' === $normalized['variable'] || '' === $normalized['operator'] ) { return false; } $order_id = isset( $context['order_id'] ) ? absint( $context['order_id'] ) : 0; if ( $order_id > 0 ) { try { $handler = new GenericCondition(); return $handler->evaluate( $normalized, $context ); } catch ( \Throwable $e ) { Log::error( 'ConditionEvaluator: GenericCondition failed', array( 'condition' => $normalized, 'error' => $e->getMessage(), ) ); return false; } } return self::evaluate_from_snapshot( $normalized, $context ); } /** * Evaluate against the order snapshot when no live order is available (e.g. abandoned cart). * * @param array $condition Normalized condition. * @param array $context Context. * @return bool */ private static function evaluate_from_snapshot( array $condition, array $context ): bool { $handler = new GenericCondition(); $actual = self::resolve_field_value( $condition['variable'], $context ); if ( null === $actual || '' === $actual ) { return false; } try { return $handler->compare( $condition['operator'], $actual, $condition['value'] ); } catch ( \Throwable $e ) { Log::error( 'ConditionEvaluator: snapshot operator failed', array( 'condition' => $condition, 'error' => $e->getMessage(), ) ); return false; } } /** * @param array $condition Condition. * @return string */ private static function field_name( array $condition ): string { $field = trim( (string) ( $condition['field'] ?? '' ) ); if ( '' !== $field ) { return $field; } return trim( (string) ( $condition['variable'] ?? '' ) ); } /** * Resolve a field from the nested order snapshot or top-level context. * * @param string $field Field name. * @param array $context Context. * @return mixed */ private static function resolve_field_value( string $field, array $context ) { if ( '' === $field ) { return null; } $order = isset( $context['order'] ) && is_array( $context['order'] ) ? $context['order'] : array(); if ( array_key_exists( $field, $order ) ) { return $order[ $field ]; } if ( array_key_exists( $field, $context ) ) { return $context[ $field ]; } return null; } }