Contact Form & anti spam fixes
All checks were successful
Generate Build Info / build-info (push) Successful in 1s
All checks were successful
Generate Build Info / build-info (push) Successful in 1s
This commit is contained in:
270
dapper.php
270
dapper.php
@@ -1146,206 +1146,108 @@ 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'] = '';
|
||||
|
||||
// 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" );
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
|
||||
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_js_token', 100);
|
||||
function dapper_cf7_js_token() {
|
||||
if (!defined('WPCF7_VERSION')) return;
|
||||
?>
|
||||
<script>
|
||||
function dapperSetToken(form) {
|
||||
let tokenField = form.querySelector('input[name="dapper_token"]');
|
||||
if (!tokenField) return;
|
||||
|
||||
add_action( 'wp_footer', 'dapper_cf7_anti_spam_js', 90 );
|
||||
function dapper_cf7_anti_spam_js() {
|
||||
if ( ! did_action( 'wpcf7_enqueue_scripts' ) ) 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();
|
||||
});
|
||||
});
|
||||
</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;
|
||||
let token = 'dpr_' + Math.random().toString(36).substring(2,12) + '_' + Date.now();
|
||||
tokenField.value = token;
|
||||
}
|
||||
|
||||
if ( get_option( 'dapper_enable_cf7_human_checkbox', 'on' ) !== 'on' ) {
|
||||
return $output;
|
||||
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('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;
|
||||
}
|
||||
|
||||
dapper_debug_log( 'Universal CF7 shortcode filter FIRED - processing form ID: ' . ( $attr['id'] ?? 'unknown' ) );
|
||||
|
||||
$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 );
|
||||
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;
|
||||
}
|
||||
|
||||
if ( strpos( $output, $checkbox_html ) === false ) {
|
||||
$output .= $checkbox_html; // Last resort append
|
||||
dapper_debug_log( 'Universal CF7 fallback append used for shortcode/widget' );
|
||||
$elapsed = time() - (int)$data['dapper_ts'];
|
||||
|
||||
if ($elapsed < 3) {
|
||||
dapper_debug_log('BLOCKED: Too fast');
|
||||
$result->invalidate('', 'Spam detected.');
|
||||
return $result;
|
||||
}
|
||||
|
||||
dapper_debug_log( 'Universal CF7 insertion COMPLETE for shortcode' );
|
||||
// 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);
|
||||
|
||||
return $output;
|
||||
if (!$domain || strlen($domain) < 3) {
|
||||
dapper_debug_log('BLOCKED: Bad email domain');
|
||||
$result->invalidate('your-email', 'Invalid email.');
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $result;
|
||||
}
|
||||
add_filter('wpcf7_form_elements', 'dapper_cf7_honeypot');
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user