Event RSVP Form With a Guest Limit
Adds an [wpide_rsvp] shortcode for events: guests reply with their name, email and party size, replies are saved on the event post with a running total, and the form closes when it is full.
Opens WPIDE on
Code
add_action( 'template_redirect', function () {
if ( empty( $_POST['wpide_rsvp_nonce'] ) || empty( $_POST['wpide_rsvp_post'] ) ) {
return;
}
$post_id = absint( $_POST['wpide_rsvp_post'] );
$back = remove_query_arg( 'wpide_rsvp', get_permalink( $post_id ) ? get_permalink( $post_id ) : home_url( '/' ) );
$done = function ( $status ) use ( $back ) {
wp_safe_redirect( add_query_arg( 'wpide_rsvp', $status, $back ) . '#wpide-rsvp' );
exit;
};
if ( ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['wpide_rsvp_nonce'] ) ), 'wpide_rsvp_' . $post_id ) || 'publish' !== get_post_status( $post_id ) ) {
$done( 'expired' );
}
if ( ! empty( $_POST['wpide_rsvp_hp'] ) ) {
$done( 'thanks' );
}
$name = sanitize_text_field( wp_unslash( isset( $_POST['wpide_rsvp_name'] ) ? $_POST['wpide_rsvp_name'] : '' ) );
$email = strtolower( sanitize_email( wp_unslash( isset( $_POST['wpide_rsvp_email'] ) ? $_POST['wpide_rsvp_email'] : '' ) ) );
$guests = max( 1, min( 10, absint( isset( $_POST['wpide_rsvp_guests'] ) ? $_POST['wpide_rsvp_guests'] : 1 ) ) );
$limit = absint( get_post_meta( $post_id, '_wpide_rsvp_limit', true ) );
if ( '' === $name || ! is_email( $email ) ) {
$done( 'invalid' );
}
$list = get_post_meta( $post_id, '_wpide_rsvp_list', true );
$list = is_array( $list ) ? $list : array();
$total = array_sum( wp_list_pluck( $list, 'guests' ) );
if ( isset( $list[ md5( $email ) ] ) ) {
$done( 'duplicate' );
}
if ( $limit && $total + $guests > $limit ) {
$done( 'full' );
}
$list[ md5( $email ) ] = array( 'name' => $name, 'email' => $email, 'guests' => $guests, 'time' => time() );
update_post_meta( $post_id, '_wpide_rsvp_list', $list );
wp_mail( $email, 'Your RSVP for ' . wp_strip_all_tags( get_the_title( $post_id ) ), sprintf( "Hi %s,\n\nThanks for your RSVP for %d guest(s). See you there!\n\n%s", $name, $guests, get_permalink( $post_id ) ) );
$done( 'thanks' );
} );
add_shortcode( 'wpide_rsvp', function ( $atts ) {
$atts = shortcode_atts( array( 'limit' => 0 ), $atts, 'wpide_rsvp' );
$post_id = get_the_ID();
if ( ! $post_id ) {
return '';
}
if ( (int) get_post_meta( $post_id, '_wpide_rsvp_limit', true ) !== (int) $atts['limit'] && current_user_can( 'edit_post', $post_id ) ) {
update_post_meta( $post_id, '_wpide_rsvp_limit', absint( $atts['limit'] ) );
}
$list = get_post_meta( $post_id, '_wpide_rsvp_list', true );
$total = is_array( $list ) ? array_sum( wp_list_pluck( $list, 'guests' ) ) : 0;
$limit = absint( $atts['limit'] );
$left = $limit ? max( 0, $limit - $total ) : null;
$messages = array(
'thanks' => 'Thank you! Your RSVP is confirmed and a confirmation email is on its way.',
'duplicate' => 'This email address has already replied.',
'full' => 'Sorry, there are not enough places left for your party.',
'invalid' => 'Please enter your name and a valid email address.',
'expired' => 'The form expired. Please try again.',
);
$status = isset( $_GET['wpide_rsvp'] ) ? sanitize_key( $_GET['wpide_rsvp'] ) : '';
$html = '<div id="wpide-rsvp" class="wpide-form wpide-rsvp">';
$html .= isset( $messages[ $status ] ) ? '<p class="wpide-form-notice" role="status">' . esc_html( $messages[ $status ] ) . '</p>' : '';
if ( null !== $left && 0 === $left ) {
return $html . '<p><strong>This event is fully booked.</strong></p></div>';
}
$html .= null !== $left ? '<p>' . esc_html( sprintf( '%d place(s) left.', $left ) ) . '</p>' : '';
$html .= '<form method="post" action="">';
$html .= '<p><label for="wpide-rsvp-name">Name</label><br><input id="wpide-rsvp-name" name="wpide_rsvp_name" required autocomplete="name"></p>';
$html .= '<p><label for="wpide-rsvp-email">Email</label><br><input type="email" id="wpide-rsvp-email" name="wpide_rsvp_email" required autocomplete="email"></p>';
$html .= '<p><label for="wpide-rsvp-guests">Number of guests (including you)</label><br><input type="number" id="wpide-rsvp-guests" name="wpide_rsvp_guests" min="1" max="10" value="1"></p>';
$html .= '<p style="position:absolute;left:-9999px;" aria-hidden="true"><input name="wpide_rsvp_hp" tabindex="-1" autocomplete="off"></p>';
$html .= '<input type="hidden" name="wpide_rsvp_post" value="' . esc_attr( $post_id ) . '">';
$html .= wp_nonce_field( 'wpide_rsvp_' . $post_id, 'wpide_rsvp_nonce', false, false );
$html .= '<p><button type="submit">RSVP</button></p></form></div>';
return $html;
} );
add_action( 'add_meta_boxes', function ( $post_type, $post ) {
if ( $post && get_post_meta( $post->ID, '_wpide_rsvp_list', true ) ) {
add_meta_box( 'wpide-rsvp-list', 'RSVPs', function ( $post ) {
$list = (array) get_post_meta( $post->ID, '_wpide_rsvp_list', true );
printf( '<p><strong>%d guest(s)</strong> from %d replies</p><ul>', (int) array_sum( wp_list_pluck( $list, 'guests' ) ), count( $list ) );
foreach ( $list as $row ) {
printf( '<li>%s <%s> × %d</li>', esc_html( $row['name'] ), esc_html( $row['email'] ), (int) $row['guests'] );
}
echo '</ul>';
}, null, 'side' );
}
}, 10, 2 );
Notes
Use [wpide_rsvp limit="50"] on the event post or page; each email address can reply once and the guest list appears in a box on that post's edit screen.
How to add this snippet
- Install WPIDE on your WordPress site (it is free) and open Code Snippets.
- Use snippet above adds it from the library in one click. Or copy the code into a new snippet with the same code type.
- It is added inactive: review the code and settings, then switch it on.