Not a problem! To count submissions on a per-post basis, that means each post will need to be responsible for counting it’s own submissions, so we’ll use a post meta field for that.
To avoid accidentally miscounting, the snippet I’m writing here will fire only when the form is submitted. The code you were using looks to pre-fill a form field with the current submission and increment it, but that number could be incorrect if person A opens the page first before person B, but then person B submits the form before person A.
/**
* Custom Email Behavior on Form Submission
*
* Copy emails based on committees selected in Volunteer form
*
* @param WPCF7_ContactForm $contact_form The current contact form.
* @param bool $abort If the submission is being aborted.
* @param WPCF7_Submission $submission The current submission data.
*
* @return null
*/
function ferda2_post_submission_counter($contact_form, &$abort, $submission)
{
$post_id = $submission->get_meta('container_post_id'); // Identify the post this form was submitted on
if ($post_id) {
$meta_key = sanitize_key('_cf7_submissions_' . $contact_form->id); // Custom meta key identifying form ID
$count = get_post_meta($post_id, $meta_key, true); // Get the current counter
if (is_int($count)) {
$count++; // Increment it if it already exists
} else {
$count = 1; // Set it to 1 if it's the first
}
update_post_meta($post_id, $meta_key, $count); // Save/create the counter to the post
}
}
add_action('wpcf7_before_send_mail', 'ferda2_post_submission_counter', 10, 3);
To then optionally display the form based on the counter, you’ll need to write a custom shortcode to replace the contact form’s shortcode in the post content. So you’ll need a function like this:
/**
* Conditionally show Contact Form
*
* @param array $atts Optional. An array of shortcode attributes including
form_id
(string) and limit
(integer).
*
* @return string The contact form 7 output on success, default text when limit has been exceeded, empty string on failure.
*/
function ferda2_limit_post_submission($atts = array())
{
// Normalize attribute keys to lowercase and configure default values
$atts = shortcode_atts(array(
'form_id' => '',
'limit' => 10 // Set default maximum limit here
), array_change_key_case((array)$atts, CASE_LOWER));
// Sanitize & validate form ID
$form_id = trim(sanitize_text_field($atts['form_id']));
if (!$form_id) {
return ''; // Empty form id, bail
}
// Sanitize & validate limit
$limit = intval(trim(sanitize_text_field($atts['limit'])));
if (!is_int($limit) || $limit < 0) {
return ''; // Invalid limit, bail
}
global $post;
$meta_key = sanitize_key('_cf7_submissions_' . $form_id); // Custom meta key identifying form ID
$count = get_post_meta($post->ID, $meta_key, true); // Get the current counter
if (
(is_int($count) && $count <= $limit) || // Count exists and is still under the limit
!$count // Count does not yet exist (probably no submissions yet)
) {
return do_shortcode(sprintf('[contact-form-7 id="%s"]', $form_id));
}
return 'Registration is closed!'; // Or whatever you want to display instead of the form
}
add_shortcode('ferda2_limit_post_submissions', 'ferda2_limit_post_submissions');
And then in the page content, you’d replace the contact form 7 shortcode with the custom one, so remove [contact-form-7 id="123" title="My Form"]
with [ferda2_limit_post_submissions form_id="123"]
I have it set so that the default limit is 10
in the shortcode, but you can change that to whatever you need. Additionally, if the limit is different for each post, you can pass that in the shortcode like this:[ferda2_limit_post_submissions form_id="123" limit="50"]
Now there is less likely to be a miscount since the counting number is only incremented when the form is submitted, but you might still run into the issue where the form is displayed if Person B was the 10th submission but Person A still has the form open on their screen. This doesn’t stop Person A from submitting, it just means if they refresh the page, they’ll see the “Registration is closed!” message. However, that is much more complex to prevent since you’d likely need some kind of background JS to ping the server for the current count and then hide the form (or whatever happens) if the limit is met while they have the page still open. Depending on your expected traffic though, this may not be a concern.
Please let me know if you have any issues!