Contact Form & anti spam fixes
All checks were successful
Generate Build Info / build-info (push) Successful in 1s

This commit is contained in:
carpentryplus25
2026-03-18 22:30:18 -04:00
parent fc6cdb6fd6
commit 765d3f5d94

View File

@@ -1146,205 +1146,107 @@ add_action( 'plugins_loaded', 'dapper_woo_conditional_load' ); // Late hook
// ────────────────────────────────────────────────
if ( class_exists( 'WPCF7' ) ) {
// 1. Old honeypot + token + speed check (keep it — layers are good)
add_action( 'wpcf7_before_send_mail', 'dapper_cf7_human_check', 9, 3 );
function dapper_cf7_human_check( $contact_form, &$abort, $submission ) {
$form_id = $contact_form->id();
$posted = $_POST;
// Add hidden fields to Contact Form 7 forms
add_filter('wpcf7_form_hidden_fields', 'dapper_cf7_hidden_fields');
function dapper_cf7_hidden_fields($fields) {
// Speed check
$posted_time = isset( $posted['dapper_cf7_time'] ) ? (int) $posted['dapper_cf7_time'] : 0;
if ( $posted_time && ( time() - $posted_time < 5 ) ) {
$abort = true;
$submission->add_error( 'dapper_speed', 'Submission too fast — please try again.' );
dapper_debug_log( "CF7 #$form_id blocked — too fast" );
return;
$fields['dapper_ts'] = time();
$fields['dapper_token'] = '';
return $fields;
}
// Honeypot
foreach ( $posted as $key => $val ) {
if ( strpos( $key, 'dapper_cf7_hp_' ) === 0 && strlen( trim( $val ) ) > 0 ) {
$abort = true;
$submission->add_error( 'dapper_honeypot', 'Spam detected.' );
dapper_debug_log( "CF7 #$form_id blocked — honeypot filled" );
return;
}
}
// Old JS token (keep for extra layer)
$token = trim( $posted['dapper_cf7_token'] ?? '' );
if ( empty( $token ) || strpos( $token, 'cf7human_' ) !== 0 ) {
$abort = true;
$submission->add_error( 'dapper_js', 'Please enable JavaScript and try again.' );
dapper_debug_log( "CF7 #$form_id blocked — missing/invalid JS token" );
}
}
add_filter( 'wpcf7_form_elements', 'dapper_cf7_inject_anti_spam_fields' );
function dapper_cf7_inject_anti_spam_fields( $form ) {
$honeypot_name = 'dapper_cf7_hp_' . wp_generate_password( 7, false );
$hidden_fields = '
<input type="hidden" name="dapper_cf7_time" value="' . time() . '" />
<input type="hidden" name="dapper_cf7_token" id="dapper_cf7_token" value="" />
<p style="position:absolute; left:-9999px; height:1px; overflow:hidden;">
<input type="text" name="' . esc_attr( $honeypot_name ) . '" value="" autocomplete="off" tabindex="-1" />
</p>';
return str_replace( '</form>', $hidden_fields . '</form>', $form );
}
add_action( 'wp_footer', 'dapper_cf7_anti_spam_js', 90 );
function dapper_cf7_anti_spam_js() {
if ( ! did_action( 'wpcf7_enqueue_scripts' ) ) return;
add_action('wp_footer', 'dapper_cf7_js_token', 100);
function dapper_cf7_js_token() {
if (!defined('WPCF7_VERSION')) return;
?>
<script>
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('.wpcf7 form').forEach(form => {
const tokenField = form.querySelector('#dapper_cf7_token');
if (tokenField) tokenField.value = 'cf7human_' + Math.random().toString(36).substring(2) + '_' + Date.now();
function dapperSetToken(form) {
let tokenField = form.querySelector('input[name="dapper_token"]');
if (!tokenField) return;
let token = 'dpr_' + Math.random().toString(36).substring(2,12) + '_' + Date.now();
tokenField.value = token;
}
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('.wpcf7 form').forEach(dapperSetToken);
});
// CRITICAL: CF7 AJAX reload hook
document.addEventListener('wpcf7beforesubmit', function(event) {
dapperSetToken(event.target);
});
</script>
<?php
}
add_filter( 'do_shortcode_tag', 'dapper_cf7_universal_insert_checkbox', 10, 4 );
function dapper_cf7_universal_insert_checkbox( $output, $tag, $attr, $m ) {
if ( $tag !== 'contact-form-7' ) {
return $output;
add_filter('wpcf7_validate', 'dapper_cf7_validate', 20, 2);
function dapper_cf7_validate($result, $tags) {
$submission = WPCF7_Submission::get_instance();
if (!$submission) return $result;
$data = $submission->get_posted_data();
// 0. HONEYPOT CHECK (FIRST LINE OF DEFENSE)
if (!empty($data['dapper_hp'])) {
dapper_debug_log('BLOCKED: Honeypot triggered');
$result->invalidate('', 'Spam detected.');
return $result;
}
if ( get_option( 'dapper_enable_cf7_human_checkbox', 'on' ) !== 'on' ) {
return $output;
dapper_debug_log('CF7 VALIDATION FIRED');
// 1. JS TOKEN REQUIRED
if (empty($data['dapper_token']) || strpos($data['dapper_token'], 'dpr_') !== 0) {
dapper_debug_log('BLOCKED: Missing JS token');
$result->invalidate('', 'Spam detected.');
return $result;
}
// 2. TIME CHECK
if (empty($data['dapper_ts'])) {
dapper_debug_log('BLOCKED: Missing timestamp');
$result->invalidate('', 'Spam detected.');
return $result;
}
dapper_debug_log( 'Universal CF7 shortcode filter FIRED - processing form ID: ' . ( $attr['id'] ?? 'unknown' ) );
$elapsed = time() - (int)$data['dapper_ts'];
$unique = uniqid();
$checkbox_html = '
<div class="dapper-cf7-human-check" style="margin: 1.5em 0; padding: 1em; background: #f8f9fa; border: 1px solid #ccd0d4; border-radius: 4px; text-align: center;">
<label style="font-size: 1.1em; cursor: pointer; user-select: none;">
<input type="checkbox" name="dapper_cf7_human_confirm" id="dapper_cf7_human_confirm_' . $unique . '" value="1" required style="transform: scale(1.4); margin-right: 0.8em; vertical-align: middle;">
I am human / not a robot
</label>
<input type="hidden" name="dapper_cf7_human_token" id="dapper_cf7_human_token_' . $unique . '" value="">
<input type="hidden" name="dapper_cf7_human_time" value="' . time() . '">
<p style="margin: 0.6em 0 0; font-size: 0.9em; color: #555;">Quick check to help stop spam. Thanks!</p>
</div>';
// Insert after response div or before </form> — aggressive match
$output = preg_replace( '/(<div class="wpcf7-response-output"[^>]*>.*?<\/div>)/is', '$1' . $checkbox_html, $output, 1 );
if ( strpos( $output, $checkbox_html ) === false ) {
$output = str_replace( '</form>', $checkbox_html . '</form>', $output );
if ($elapsed < 3) {
dapper_debug_log('BLOCKED: Too fast');
$result->invalidate('', 'Spam detected.');
return $result;
}
if ( strpos( $output, $checkbox_html ) === false ) {
$output .= $checkbox_html; // Last resort append
dapper_debug_log( 'Universal CF7 fallback append used for shortcode/widget' );
// 3. EMAIL PROTECTION
if (!empty($data['your-email'])) {
$email = sanitize_email($data['your-email']);
if (!is_email($email)) {
dapper_debug_log('BLOCKED: Invalid email');
$result->invalidate('your-email', 'Invalid email.');
return $result;
}
if (preg_match('/(test|asdf|123|spam)/i', $email)) {
dapper_debug_log('BLOCKED: Suspicious email');
$result->invalidate('your-email', 'Invalid email.');
return $result;
}
$domain = substr(strrchr($email, "@"), 1);
dapper_debug_log( 'Universal CF7 insertion COMPLETE for shortcode' );
return $output;
if (!$domain || strlen($domain) < 3) {
dapper_debug_log('BLOCKED: Bad email domain');
$result->invalidate('your-email', 'Invalid email.');
return $result;
}
}
// 2. NEW: Visible checkbox — use reliable append method
add_filter( 'wpcf7_form_elements', 'dapper_cf7_append_human_checkbox', 100 ); // Higher priority = later
function dapper_cf7_append_human_checkbox( $form ) {
if ( get_option( 'dapper_enable_cf7_human_checkbox', 'on' ) !== 'on' ) {
return $form;
return $result;
}
add_filter('wpcf7_form_elements', 'dapper_cf7_honeypot');
// Debug: Confirm filter is firing (now using your helper)
dapper_debug_log( 'CF7 checkbox filter FIRED - form length before insert: ' . strlen( $form ) );
$unique = uniqid();
$checkbox_html = '
<div class="dapper-cf7-human-check" style="margin: 1.5em 0; padding: 1em; background: #f8f9fa; border: 1px solid #ccd0d4; border-radius: 4px; text-align: center;">
<label style="font-size: 1.1em; cursor: pointer; user-select: none;">
<input type="checkbox" name="dapper_cf7_human_confirm" id="dapper_cf7_human_confirm_' . $unique . '" value="1" required style="transform: scale(1.4); margin-right: 0.8em; vertical-align: middle;">
I am human / not a robot
</label>
<input type="hidden" name="dapper_cf7_human_token" id="dapper_cf7_human_token_' . $unique . '" value="">
<input type="hidden" name="dapper_cf7_human_time" value="' . time() . '">
<p style="margin: 0.6em 0 0; font-size: 0.9em; color: #555;">Quick check to help stop spam. Thanks!</p>
</div>';
// 1. Try after the response output div (common in widgets/Flatsome)
$form = preg_replace( '/(<div class="wpcf7-response-output"[^>]*>.*?<\/div>)/is', '$1' . $checkbox_html, $form, 1 );
// 2. If not found, insert before </form>
if ( strpos( $form, $checkbox_html ) === false ) {
$form = str_replace( '</form>', $checkbox_html . '</form>', $form );
}
// 3. Ultimate fallback: just append to the end
if ( strpos( $form, $checkbox_html ) === false ) {
$form .= $checkbox_html;
dapper_debug_log( 'CF7 checkbox FALLBACK append used (no </form> or response div match)' );
}
dapper_debug_log( 'CF7 checkbox filter COMPLETE - insertion attempted' );
return $form;
}
// Tiny JS to set token + disable submit until checked
add_action( 'wp_footer', 'dapper_cf7_human_checkbox_js', 100 );
function dapper_cf7_human_checkbox_js() {
if ( ! did_action( 'wpcf7_enqueue_scripts' ) ) return;
?>
<script>
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('.wpcf7 form').forEach(form => {
const chk = form.querySelector('input[name="dapper_cf7_human_confirm"]');
const tok = form.querySelector('input[name="dapper_cf7_human_token"]');
const btn = form.querySelector('input[type="submit"], button[type="submit"]');
if (!chk || !tok || !btn) return;
// Disable submit until checked
btn.disabled = true;
chk.addEventListener('change', () => {
tok.value = chk.checked ? 'cf7_human_' + Math.random().toString(36).substring(2,12) + '_' + Date.now() : '';
btn.disabled = !chk.checked;
});
});
});
</script>
<?php
}
// Server-side validation for checkbox
add_action( 'wpcf7_before_send_mail', 'dapper_cf7_validate_human_checkbox', 12, 3 );
function dapper_cf7_validate_human_checkbox( $contact_form, &$abort, $submission ) {
if ( get_option( 'dapper_enable_cf7_human_checkbox', 'on' ) !== 'on' ) return;
$posted = $_POST;
if ( empty( $posted['dapper_cf7_human_confirm'] ) ) {
$abort = true;
$submission->add_error( 'dapper_human', 'Please confirm you are human.' );
dapper_debug_log( "CF7 #{$contact_form->id()} blocked — checkbox not checked" );
return;
}
$token = trim( $posted['dapper_cf7_human_token'] ?? '' );
if ( empty( $token ) || strpos( $token, 'cf7_human_' ) !== 0 || strlen( $token ) < 20 ) {
$abort = true;
$submission->add_error( 'dapper_human', 'Verification failed — please try again.' );
dapper_debug_log( "CF7 #{$contact_form->id()} blocked — invalid/missing human token" );
return;
}
$time = (int) ( $posted['dapper_cf7_human_time'] ?? 0 );
if ( $time && ( time() - $time < 4 ) ) {
$abort = true;
$submission->add_error( 'dapper_human', 'Submission too fast — please try again.' );
dapper_debug_log( "CF7 #{$contact_form->id()} blocked — human check too fast" );
}
function dapper_cf7_honeypot($form) {
$hp = '<span style="display:none;">
<input type="text" name="dapper_hp" value="">
</span>';
return $hp . $form;
}
}