<?php add_action('wpcf7_init', 'wpcf7_recaptcha_register_service', 15, 0); function wpcf7_recaptcha_register_service() { $integration = WPCF7_Integration::get_instance(); $integration->add_category('captcha', __('CAPTCHA', 'contact-form-7')); $integration->add_service('recaptcha', WPCF7_RECAPTCHA::get_instance()); } add_action('wp_enqueue_scripts', 'wpcf7_recaptcha_enqueue_scripts', 20, 0); function wpcf7_recaptcha_enqueue_scripts() { $service = WPCF7_RECAPTCHA::get_instance(); if (!$service->is_active()) { return; } $url = 'https://www.google.com/recaptcha/api.js'; if (apply_filters('wpcf7_use_recaptcha_net', false)) { $url = 'https://www.recaptcha.net/recaptcha/api.js'; } wp_enqueue_script('google-recaptcha', add_query_arg(array('render' => $service->get_sitekey()), $url), array(), '3.0', true); $assets = array(); $asset_file = wpcf7_plugin_path('modules/recaptcha/index.asset.php'); if (file_exists($asset_file)) { $assets = (include $asset_file); } $assets = wp_parse_args($assets, array('src' => wpcf7_plugin_url('modules/recaptcha/index.js'), 'dependencies' => array('google-recaptcha', 'wp-polyfill'), 'version' => WPCF7_VERSION, 'in_footer' => true)); wp_register_script('wpcf7-recaptcha', $assets['src'], $assets['dependencies'], $assets['version'], $assets['in_footer']); wp_enqueue_script('wpcf7-recaptcha'); wp_localize_script('wpcf7-recaptcha', 'wpcf7_recaptcha', array('sitekey' => $service->get_sitekey(), 'actions' => apply_filters('wpcf7_recaptcha_actions', array('homepage' => 'homepage', 'contactform' => 'contactform')))); } add_filter('wpcf7_form_hidden_fields', 'wpcf7_recaptcha_add_hidden_fields', 100, 1); function wpcf7_recaptcha_add_hidden_fields($fields) { $service = WPCF7_RECAPTCHA::get_instance(); if (!$service->is_active()) { return $fields; } return array_merge($fields, array('_wpcf7_recaptcha_response' => '')); } add_filter('wpcf7_spam', 'wpcf7_recaptcha_verify_response', 9, 2); function wpcf7_recaptcha_verify_response($spam, $submission) { if ($spam) { return $spam; } $service = WPCF7_RECAPTCHA::get_instance(); if (!$service->is_active()) { return $spam; } $token = isset($_POST['_wpcf7_recaptcha_response']) ? trim($_POST['_wpcf7_recaptcha_response']) : ''; if ($service->verify($token)) { $spam = false; } else { $spam = true; if ('' === $token) { $submission->add_spam_log(array('agent' => 'recaptcha', 'reason' => __('reCAPTCHA response token is empty.', 'contact-form-7'))); } else { $submission->add_spam_log(array('agent' => 'recaptcha', 'reason' => sprintf(__('reCAPTCHA score (%1$.2f) is lower than the threshold (%2$.2f).', 'contact-form-7'), $service->get_last_score(), $service->get_threshold()))); } } return $spam; } add_action('wpcf7_init', 'wpcf7_recaptcha_add_form_tag_recaptcha', 10, 0); function wpcf7_recaptcha_add_form_tag_recaptcha() { $service = WPCF7_RECAPTCHA::get_instance(); if (!$service->is_active()) { return; } wpcf7_add_form_tag('recaptcha', '__return_empty_string', array('display-block' => true)); } add_action('wpcf7_upgrade', 'wpcf7_upgrade_recaptcha_v2_v3', 10, 2); function wpcf7_upgrade_recaptcha_v2_v3($new_ver, $old_ver) { if (version_compare('5.1-dev', $old_ver, '<=')) { return; } $service = WPCF7_RECAPTCHA::get_instance(); if (!$service->is_active() or $service->get_global_sitekey()) { return; } WPCF7::update_option('recaptcha_v2_v3_warning', true); WPCF7::update_option('recaptcha', null); } add_action('wpcf7_admin_menu', 'wpcf7_admin_init_recaptcha_v2_v3', 10, 0); function wpcf7_admin_init_recaptcha_v2_v3() { if (!WPCF7::get_option('recaptcha_v2_v3_warning')) { return; } add_filter('wpcf7_admin_menu_change_notice', 'wpcf7_admin_menu_change_notice_recaptcha_v2_v3', 10, 1); add_action('wpcf7_admin_warnings', 'wpcf7_admin_warnings_recaptcha_v2_v3', 5, 3); } function wpcf7_admin_menu_change_notice_recaptcha_v2_v3($counts) { $counts['wpcf7-integration'] += 1; return $counts; } function wpcf7_admin_warnings_recaptcha_v2_v3($page, $action, $object) { if ('wpcf7-integration' !== $page) { return; } $message = sprintf(esc_html(__("API keys for reCAPTCHA v3 are different from those for v2; keys for v2 don&#8217;t work with the v3 API. You need to register your sites again to get new keys for v3. For details, see %s.", 'contact-form-7')), wpcf7_link(__('https://contactform7.com/recaptcha/', 'contact-form-7'), __('reCAPTCHA (v3)', 'contact-form-7'))); echo sprintf('<div class="notice notice-warning"><p>%s</p></div>', $message); } if (!class_exists('WPCF7_Service')) { return; } class WPCF7_RECAPTCHA extends WPCF7_Service { private static $instance; private $sitekeys; private $last_score; public static function get_instance() { if (empty(self::$instance)) { self::$instance = new self(); } return self::$instance; } private function __construct() { $this->sitekeys = WPCF7::get_option('recaptcha'); } public function get_title() { return __('reCAPTCHA', 'contact-form-7'); } public function is_active() { $sitekey = $this->get_sitekey(); $secret = $this->get_secret($sitekey); return $sitekey && $secret; } public function get_categories() { return array('captcha'); } public function icon() { } public function link() { echo wpcf7_link('https://www.google.com/recaptcha/intro/index.html', 'google.com/recaptcha'); } public function get_global_sitekey() { static $sitekey = ''; if ($sitekey) { return $sitekey; } if (defined('WPCF7_RECAPTCHA_SITEKEY')) { $sitekey = WPCF7_RECAPTCHA_SITEKEY; } $sitekey = apply_filters('wpcf7_recaptcha_sitekey', $sitekey); return $sitekey; } public function get_global_secret() { static $secret = ''; if ($secret) { return $secret; } if (defined('WPCF7_RECAPTCHA_SECRET')) { $secret = WPCF7_RECAPTCHA_SECRET; } $secret = apply_filters('wpcf7_recaptcha_secret', $secret); return $secret; } public function get_sitekey() { if ($this->get_global_sitekey() && $this->get_global_secret()) { return $this->get_global_sitekey(); } if (empty($this->sitekeys) or !is_array($this->sitekeys)) { return false; } $sitekeys = array_keys($this->sitekeys); return $sitekeys[0]; } public function get_secret($sitekey) { if ($this->get_global_sitekey() && $this->get_global_secret()) { return $this->get_global_secret(); } $sitekeys = (array) $this->sitekeys; if (isset($sitekeys[$sitekey])) { return $sitekeys[$sitekey]; } else { return false; } } protected function log($url, $request, $response) { wpcf7_log_remote_request($url, $request, $response); } public function verify($token) { $is_human = false; if (empty($token) or !$this->is_active()) { return $is_human; } $endpoint = 'https://www.google.com/recaptcha/api/siteverify'; $sitekey = $this->get_sitekey(); $secret = $this->get_secret($sitekey); $request = array('body' => array('secret' => $secret, 'response' => $token)); $response = wp_remote_post(esc_url_raw($endpoint), $request); if (200 != wp_remote_retrieve_response_code($response)) { if (WP_DEBUG) { $this->log($endpoint, $request, $response); } return $is_human; } $response_body = wp_remote_retrieve_body($response); $response_body = json_decode($response_body, true); $this->last_score = $score = isset($response_body['score']) ? $response_body['score'] : 0; $threshold = $this->get_threshold(); $is_human = $threshold < $score; $is_human = apply_filters('wpcf7_recaptcha_verify_response', $is_human, $response_body); if ($submission = WPCF7_Submission::get_instance()) { $submission->recaptcha = array('version' => '3.0', 'threshold' => $threshold, 'response' => $response_body); } return $is_human; } public function get_threshold() { return apply_filters('wpcf7_recaptcha_threshold', 0.5); } public function get_last_score() { return $this->last_score; } protected function menu_page_url($args = '') { $args = wp_parse_args($args, array()); $url = menu_page_url('wpcf7-integration', false); $url = add_query_arg(array('service' => 'recaptcha'), $url); if (!empty($args)) { $url = add_query_arg($args, $url); } return $url; } protected function save_data() { WPCF7::update_option('recaptcha', $this->sitekeys); } protected function reset_data() { $this->sitekeys = null; $this->save_data(); } public function load($action = '') { if ('setup' == $action and 'POST' == $_SERVER['REQUEST_METHOD']) { check_admin_referer('wpcf7-recaptcha-setup'); if (!empty($_POST['reset'])) { $this->reset_data(); $redirect_to = $this->menu_page_url('action=setup'); } else { $sitekey = isset($_POST['sitekey']) ? trim($_POST['sitekey']) : ''; $secret = isset($_POST['secret']) ? trim($_POST['secret']) : ''; if ($sitekey and $secret) { $this->sitekeys = array($sitekey => $secret); $this->save_data(); $redirect_to = $this->menu_page_url(array('message' => 'success')); } else { $redirect_to = $this->menu_page_url(array('action' => 'setup', 'message' => 'invalid')); } } if (WPCF7::get_option('recaptcha_v2_v3_warning')) { WPCF7::update_option('recaptcha_v2_v3_warning', false); } wp_safe_redirect($redirect_to); exit; } } public function admin_notice($message = '') { if ('invalid' == $message) { echo sprintf('<div class="notice notice-error"><p><strong>%1$s</strong>: %2$s</p></div>', esc_html(__("Error", 'contact-form-7')), esc_html(__("Invalid key values.", 'contact-form-7'))); } if ('success' == $message) { echo sprintf('<div class="notice notice-success"><p>%s</p></div>', esc_html(__('Settings saved.', 'contact-form-7'))); } } public function display($action = '') { echo '<p>' . sprintf(esc_html(__('reCAPTCHA protects you against spam and other types of automated abuse. With Contact Form 7&#8217;s reCAPTCHA integration module, you can block abusive form submissions by spam bots. For details, see %s.', 'contact-form-7')), wpcf7_link(__('https://contactform7.com/recaptcha/', 'contact-form-7'), __('reCAPTCHA (v3)', 'contact-form-7'))) . '</p>'; if ($this->is_active()) { echo sprintf('<p class="dashicons-before dashicons-yes">%s</p>', esc_html(__("reCAPTCHA is active on this site.", 'contact-form-7'))); } if ('setup' == $action) { $this->display_setup(); } else { echo sprintf('<p><a href="%1$s" class="button">%2$s</a></p>', esc_url($this->menu_page_url('action=setup')), esc_html(__('Setup Integration', 'contact-form-7'))); } } private function display_setup() { $sitekey = $this->is_active() ? $this->get_sitekey() : ''; $secret = $this->is_active() ? $this->get_secret($sitekey) : ''; ?> <form method="post" action="<?php echo esc_url($this->menu_page_url('action=setup')); ?>"> <?php wp_nonce_field('wpcf7-recaptcha-setup'); ?> <table class="form-table"> <tbody> <tr> <th scope="row"><label for="sitekey"><?php echo esc_html(__('Site Key', 'contact-form-7')); ?></label></th> <td><?php if ($this->is_active()) { echo esc_html($sitekey); echo sprintf('<input type="hidden" value="%1$s" id="sitekey" name="sitekey" />', esc_attr($sitekey)); } else { echo sprintf('<input type="text" aria-required="true" value="%1$s" id="sitekey" name="sitekey" class="regular-text code" />', esc_attr($sitekey)); } ?></td> </tr> <tr> <th scope="row"><label for="secret"><?php echo esc_html(__('Secret Key', 'contact-form-7')); ?></label></th> <td><?php if ($this->is_active()) { echo esc_html(wpcf7_mask_password($secret, 4, 4)); echo sprintf('<input type="hidden" value="%1$s" id="secret" name="secret" />', esc_attr($secret)); } else { echo sprintf('<input type="text" aria-required="true" value="%1$s" id="secret" name="secret" class="regular-text code" />', esc_attr($secret)); } ?></td> </tr> </tbody> </table> <?php if ($this->is_active()) { if ($this->get_global_sitekey() && $this->get_global_secret()) { } else { submit_button(_x('Remove Keys', 'API keys', 'contact-form-7'), 'small', 'reset'); } } else { submit_button(__('Save Changes', 'contact-form-7')); } ?> </form> <?php } }