trigger_type = $trigger_type; if( empty($this->trigger_type) ) { return; } } static function run_notifications( $trigger_type = '', $data = [] ) { $self = new self( $trigger_type ); $all_notifications = $self->get_all_notifications(); if (empty($all_notifications)) { return; } foreach ($all_notifications as $notification) { if ($self->check_notification_conditions($notification, $data)) { do_action('pisol_anfw_send_notification', $notification->id, $data); } } } private function get_all_notifications() { $notifications = array(); // Get all published notifications from the custom post type $notification_posts = get_posts(array( 'post_type' => 'pisol_anfw_notice', 'post_status' => 'publish', 'numberposts' => -1, 'meta_query' => array( array( 'key' => '_pisol_anfw_trigger', 'value' => $this->trigger_type, 'compare' => '=' ) ) )); if (empty($notification_posts)) return array(); foreach ($notification_posts as $post) { $notification = new \stdClass(); $notification->id = $post->ID; $notification->name = $post->post_title; $notification->conditions = get_post_meta($post->ID, '_pisol_anfw_conditions', true); $notifications[] = $notification; } return $notifications; } private function check_notification_conditions($notification, $data) { if (empty($notification->conditions)) return false; $groups = $notification->conditions; if (empty($groups) || !is_array($groups)) return false; // If there are no condition groups, return false if (count($groups) === 0) return false; $group_results = array(); $group_index = 0; // Loop through each condition group and evaluate it foreach ($groups as $group_id => $group) { $result = $this->check_condition_group($group, $data); if ($result !== null) { $group_results[$group_id] = $result; $groups[$group_id]['result'] = $result; // Store the result in the group for debugging $group_index++; } } // If no valid groups were processed, return false if (empty($group_results)) { return false; } // Evaluate multiple groups with their logic operators return $this->evaluate_group_relationships($groups); } function evaluate_group_relationships($groups_results) { // Get indexed array version $items = array_values($groups_results); // Step 1: resolve all ANDs for ($i = 0; $i < count($items) - 1; $i++) { if (isset($items[$i + 1]['logic']) && strtoupper($items[$i + 1]['logic']) === 'AND') { $items[$i + 1]['result'] = $items[$i]['result'] && $items[$i + 1]['result']; $items[$i]['result'] = null; // mark as merged } } // Step 2: resolve all ORs $result = false; foreach ($items as $item) { if ($item['result'] !== null) { $result = $result || $item['result']; } } return $result; } private function check_condition_group($group, $data) { // Skip if not a valid group if (!isset($group['conditions']) || !is_array($group['conditions']) || empty($group['conditions'])) { return null; } // Get the match type (all or any) $match_type = isset($group['match_type']) ? $group['match_type'] : 'all'; // Track results for conditions in this group $condition_results = array(); // Process each condition in this group foreach ($group['conditions'] as $condition) { // Skip invalid conditions if (!isset($condition['type']) || empty($condition['type'])) { continue; } // Evaluate the condition $eval_result = $this->evaluate_condition($condition, $data); if($eval_result === null) { continue; // Skip if evaluation failed } /** * this improves the performance as we dont have to check other conditions */ if($match_type === 'all' && $eval_result === false) { return false; // If match_type is 'all' and any condition fails, return false } $condition_results[] = $eval_result; } // If no valid conditions in this group, return null if (empty($condition_results)) { return null; } // Determine if this group matches based on its match_type if ($match_type === 'all') { // All conditions must match return !in_array(false, $condition_results, true); } else { // Any condition can match return in_array(true, $condition_results, true); } } private function evaluate_condition($rule, $data) { $type = sanitize_text_field($rule['type'] ?? ''); $operator = sanitize_text_field($rule['operator'] ?? ''); $value = $rule['value'] ?? ''; // Default result is false $result = false; /** * Filter to evaluate a condition * * @param bool $result Default result (false) * @param \WC_Order $order The order object * @param string $operator The comparison operator * @param mixed $value The value to compare against * @return bool Whether the condition is met */ return apply_filters( "pisol_anfw_{$type}_is_match", $result, $data, $this->trigger_type, $operator, $value ); } }