PHP实现Contact Form7表单分组评分重复值校验及错误提示
Hey there! Let's walk through how to fix this validation issue step by step—since you're new to PHP and Contact Form7 (CF7), I'll keep things clear and explain each part.
First, Understand the Problem with Your Current Code
Your duplicate-check logic using array_unique() is actually on the right track! The main issues are:
- You're using a
$cluster1variable that doesn't exist yet—you haven't collected the form values into this array. - Contact Form7 has its own hooks to handle validation, so we can't just run this code directly in
functions.phpwithout tying it to CF7's submission process. - We also need to handle cases where a user doesn't select an option (the default "--" value) before checking for duplicates.
Step 1: Use CF7's Validation Hook
CF7 provides the wpcf7_validate hook that lets us add custom validation rules before the form is submitted. We'll use this hook to run our checks.
Step 2: Collect Values for a Cluster
Since we can't access the frontend class attribute directly in PHP, we'll use the field name pattern to group values. For your first cluster, all fields start with one- (one-01, one-02, etc.). We'll loop through the submitted form data and collect these values into an array.
Step 3: Add Validation Logic
Once we have the cluster array, we'll:
- Check if any option is still set to the default "--" (empty/unchosen value).
- Check if there are duplicate rankings using
array_unique(). - If either issue exists, we'll add an error message to the form.
Full Working Code
Add this to your child theme's functions.php file:
add_filter('wpcf7_validate', 'cf7_cluster_unique_ranking_validation', 10, 2); function cf7_cluster_unique_ranking_validation($result, $tag) { // Get all submitted form data using CF7's official method $submission = WPCF7_Submission::get_instance(); if (!$submission) return $result; $posted_data = $submission->get_posted_data(); // -------------------------- // Validate First Cluster (one-01 to one-04) // -------------------------- $cluster1 = []; // Loop through fields starting with "one-" to collect values foreach ($posted_data as $field_name => $value) { if (str_starts_with($field_name, 'one-')) { // Check if user left an option unselected if ($value === '--') { $result->invalidate($tag, 'Please select a ranking for all options in the first cluster.'); return $result; } $cluster1[] = $value; } } // Check for duplicate rankings in the cluster if (count(array_unique($cluster1)) !== count($cluster1)) { $result->invalidate($tag, 'You must use each score (1-4) only once per cluster.'); return $result; } // -------------------------- // Add More Clusters Here (e.g., cluster2 with fields starting with "two-") // -------------------------- // $cluster2 = []; // foreach ($posted_data as $field_name => $value) { // if (str_starts_with($field_name, 'two-')) { // if ($value === '--') { // $result->invalidate($tag, 'Please select a ranking for all options in the second cluster.'); // return $result; // } // $cluster2[] = $value; // } // } // if (count(array_unique($cluster2)) !== count($cluster2)) { // $result->invalidate($tag, 'You must use each score (1-4) only once per cluster.'); // return $result; // } return $result; }
Key Explanations for Beginners
- Hook into CF7: The
add_filter('wpcf7_validate', ...)line tells WordPress to run our validation function when CF7 checks the form. - Get Submitted Data:
WPCF7_Submission::get_instance()is the official CF7 way to access form data (avoid using$_POSTdirectly—it's less reliable with CF7's internal handling). - Collect Cluster Values: We loop through all posted fields and grab those starting with
one-(adjust this prefix if your other clusters use different names, liketwo-). - Check for Empty Selections: If any field is still set to "--", we show an error asking the user to fill all options.
- Check for Duplicates:
array_unique()removes duplicate values—if the length of the unique array is shorter than the original, that means there are duplicates in the rankings.
Important Notes
- Make sure your CF7 select fields keep the
--as the first option (like your original code:[select* one-01 first_as_label class:cluster1 "--" "1" "2" "3" "4"]). This ensures we can detect unselected options. - If you add more clusters (like cluster2, cluster3), just copy the cluster validation block and change the field prefix (from
one-totwo-, etc.). - Always test the form after adding this code to make sure errors show up correctly when duplicates or empty selections are present.
内容的提问来源于stack exchange,提问作者timhuk

