301 lines
8.8 KiB
PHP
301 lines
8.8 KiB
PHP
<?php
|
|
namespace ElementorPro\Modules\Forms\Classes;
|
|
|
|
use Elementor\Settings;
|
|
use Elementor\Widget_Base;
|
|
use ElementorPro\Core\Utils;
|
|
use ElementorPro\Plugin;
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit; // Exit if accessed directly
|
|
}
|
|
|
|
/**
|
|
* Integration with Google reCAPTCHA
|
|
*/
|
|
class Recaptcha_Handler {
|
|
|
|
const OPTION_NAME_SITE_KEY = 'elementor_pro_recaptcha_site_key';
|
|
|
|
const OPTION_NAME_SECRET_KEY = 'elementor_pro_recaptcha_secret_key';
|
|
|
|
const OPTION_NAME_RECAPTCHA_THRESHOLD = 'elementor_pro_recaptcha_threshold';
|
|
|
|
const V2_CHECKBOX = 'v2_checkbox';
|
|
|
|
protected static function get_recaptcha_name() {
|
|
return 'recaptcha';
|
|
}
|
|
|
|
public static function get_site_key() {
|
|
return get_option( self::OPTION_NAME_SITE_KEY );
|
|
}
|
|
|
|
public static function get_secret_key() {
|
|
return get_option( self::OPTION_NAME_SECRET_KEY );
|
|
}
|
|
|
|
public static function get_recaptcha_type() {
|
|
return self::V2_CHECKBOX;
|
|
}
|
|
|
|
public static function is_enabled() {
|
|
return static::get_site_key() && static::get_secret_key();
|
|
}
|
|
|
|
public static function get_setup_message() {
|
|
return esc_html__( 'To use reCAPTCHA, you need to add the API Key and complete the setup process in Dashboard > Elementor > Settings > Integrations > reCAPTCHA.', 'elementor-pro' );
|
|
}
|
|
|
|
public function register_admin_fields( Settings $settings ) {
|
|
$settings->add_section( Settings::TAB_INTEGRATIONS, static::get_recaptcha_name(), [
|
|
'label' => esc_html__( 'reCAPTCHA', 'elementor-pro' ),
|
|
'callback' => function () {
|
|
echo sprintf(
|
|
/* translators: 1: Link opening tag, 2: Link closing tag. */
|
|
esc_html__( '%1$sreCAPTCHA%2$s is a free service by Google that protects your website from spam and abuse. It does this while letting your valid users pass through with ease.', 'elementor-pro' ),
|
|
'<a href="https://www.google.com/recaptcha/" target="_blank">',
|
|
'</a>'
|
|
);
|
|
},
|
|
'fields' => [
|
|
'pro_recaptcha_site_key' => [
|
|
'label' => esc_html__( 'Site Key', 'elementor-pro' ),
|
|
'field_args' => [
|
|
'type' => 'text',
|
|
],
|
|
],
|
|
'pro_recaptcha_secret_key' => [
|
|
'label' => esc_html__( 'Secret Key', 'elementor-pro' ),
|
|
'field_args' => [
|
|
'type' => 'text',
|
|
],
|
|
],
|
|
],
|
|
] );
|
|
}
|
|
|
|
public function localize_settings( $settings ) {
|
|
$settings = array_replace_recursive( $settings, [
|
|
'forms' => [
|
|
static::get_recaptcha_name() => [
|
|
'enabled' => static::is_enabled(),
|
|
'type' => static::get_recaptcha_type(),
|
|
'site_key' => static::get_site_key(),
|
|
'setup_message' => static::get_setup_message(),
|
|
],
|
|
],
|
|
] );
|
|
|
|
return $settings;
|
|
}
|
|
|
|
protected static function get_script_render_param() {
|
|
return 'explicit';
|
|
}
|
|
|
|
protected static function get_script_name() {
|
|
return 'elementor-' . static::get_recaptcha_name() . '-api';
|
|
}
|
|
|
|
public function register_scripts() {
|
|
$script_name = static::get_script_name();
|
|
$src = 'https://www.google.com/recaptcha/api.js?render=explicit';
|
|
wp_register_script( $script_name, $src, [], ELEMENTOR_PRO_VERSION, true );
|
|
}
|
|
|
|
public function enqueue_scripts() {
|
|
if ( Plugin::elementor()->preview->is_preview_mode() ) {
|
|
return;
|
|
}
|
|
$script_name = static::get_script_name();
|
|
wp_enqueue_script( $script_name );
|
|
}
|
|
|
|
/**
|
|
* @param Form_Record $record
|
|
* @param Ajax_Handler $ajax_handler
|
|
*/
|
|
public function validation( $record, $ajax_handler ) {
|
|
$fields = $record->get_field( [
|
|
'type' => static::get_recaptcha_name(),
|
|
] );
|
|
|
|
if ( empty( $fields ) ) {
|
|
return;
|
|
}
|
|
|
|
$field = current( $fields );
|
|
|
|
// PHPCS - response protected by recaptcha secret
|
|
$recaptcha_response = Utils::_unstable_get_super_global_value( $_POST, 'g-recaptcha-response' ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
|
|
|
|
if ( empty( $recaptcha_response ) ) {
|
|
$ajax_handler->add_error( $field['id'], esc_html__( 'The Captcha field cannot be blank. Please enter a value.', 'elementor-pro' ) );
|
|
|
|
return;
|
|
}
|
|
|
|
$recaptcha_errors = [
|
|
'missing-input-secret' => esc_html__( 'The secret parameter is missing.', 'elementor-pro' ),
|
|
'invalid-input-secret' => esc_html__( 'The secret parameter is invalid or malformed.', 'elementor-pro' ),
|
|
'missing-input-response' => esc_html__( 'The response parameter is missing.', 'elementor-pro' ),
|
|
'invalid-input-response' => esc_html__( 'The response parameter is invalid or malformed.', 'elementor-pro' ),
|
|
];
|
|
|
|
$recaptcha_secret = static::get_secret_key();
|
|
$client_ip = Utils::get_client_ip();
|
|
|
|
$request = [
|
|
'body' => [
|
|
'secret' => $recaptcha_secret,
|
|
'response' => $recaptcha_response,
|
|
'remoteip' => $client_ip,
|
|
],
|
|
];
|
|
|
|
$response = wp_remote_post( 'https://www.google.com/recaptcha/api/siteverify', $request );
|
|
|
|
$response_code = wp_remote_retrieve_response_code( $response );
|
|
|
|
if ( 200 !== (int) $response_code ) {
|
|
/* translators: %d: Response code. */
|
|
$ajax_handler->add_error( $field['id'], sprintf( esc_html__( 'Can not connect to the reCAPTCHA server (%d).', 'elementor-pro' ), $response_code ) );
|
|
|
|
return;
|
|
}
|
|
|
|
$body = wp_remote_retrieve_body( $response );
|
|
|
|
$result = json_decode( $body, true );
|
|
|
|
if ( ! $this->validate_result( $result, $field ) ) {
|
|
$message = esc_html__( 'Invalid form, reCAPTCHA validation failed.', 'elementor-pro' );
|
|
|
|
if ( isset( $result['error-codes'] ) ) {
|
|
$result_errors = array_flip( $result['error-codes'] );
|
|
|
|
foreach ( $recaptcha_errors as $error_key => $error_desc ) {
|
|
if ( isset( $result_errors[ $error_key ] ) ) {
|
|
$message = $recaptcha_errors[ $error_key ];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->add_error( $ajax_handler, $field, $message );
|
|
|
|
}
|
|
|
|
// If success - remove the field form list (don't send it in emails and etc )
|
|
$record->remove_field( $field['id'] );
|
|
|
|
}
|
|
|
|
/**
|
|
* @param Ajax_Handler $ajax_handler
|
|
* @param $field
|
|
* @param $message
|
|
*/
|
|
protected function add_error( $ajax_handler, $field, $message ) {
|
|
$ajax_handler->add_error( $field['id'], $message );
|
|
}
|
|
|
|
protected function validate_result( $result, $field ) {
|
|
if ( ! $result['success'] ) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @param $item
|
|
* @param $item_index
|
|
* @param $widget Widget_Base
|
|
*/
|
|
public function render_field( $item, $item_index, $widget ) {
|
|
$recaptcha_html = '<div class="elementor-field" id="form-field-' . $item['custom_id'] . '">';
|
|
|
|
$recaptcha_name = static::get_recaptcha_name();
|
|
|
|
if ( static::is_enabled() ) {
|
|
$this->enqueue_scripts();
|
|
$this->add_render_attributes( $item, $item_index, $widget );
|
|
$recaptcha_html .= '<div ' . $widget->get_render_attribute_string( $recaptcha_name . $item_index ) . '></div>';
|
|
} elseif ( current_user_can( 'manage_options' ) ) {
|
|
$recaptcha_html .= '<div class="elementor-alert elementor-alert-info">';
|
|
$recaptcha_html .= static::get_setup_message();
|
|
$recaptcha_html .= '</div>';
|
|
}
|
|
|
|
$recaptcha_html .= '</div>';
|
|
|
|
// PHPCS - It's all escaped
|
|
echo $recaptcha_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
|
}
|
|
|
|
/**
|
|
* @param $item
|
|
* @param $item_index
|
|
* @param $widget Widget_Base
|
|
*/
|
|
protected function add_render_attributes( $item, $item_index, $widget ) {
|
|
$recaptcha_name = static::get_recaptcha_name();
|
|
|
|
$widget->add_render_attribute( [
|
|
$recaptcha_name . $item_index => [
|
|
'class' => 'elementor-g-recaptcha',
|
|
'data-sitekey' => static::get_site_key(),
|
|
'data-type' => static::get_recaptcha_type(),
|
|
],
|
|
] );
|
|
|
|
$this->add_version_specific_render_attributes( $item, $item_index, $widget );
|
|
}
|
|
|
|
/**
|
|
* @param $item
|
|
* @param $item_index
|
|
* @param $widget Widget_Base
|
|
*/
|
|
protected function add_version_specific_render_attributes( $item, $item_index, $widget ) {
|
|
$recaptcha_name = static::get_recaptcha_name();
|
|
$widget->add_render_attribute( $recaptcha_name . $item_index, [
|
|
'data-theme' => $item['recaptcha_style'],
|
|
'data-size' => $item['recaptcha_size'],
|
|
] );
|
|
}
|
|
|
|
public function add_field_type( $field_types ) {
|
|
$field_types['recaptcha'] = esc_html__( 'reCAPTCHA', 'elementor-pro' );
|
|
|
|
return $field_types;
|
|
}
|
|
|
|
public function filter_field_item( $item ) {
|
|
if ( static::get_recaptcha_name() === $item['field_type'] ) {
|
|
$item['field_label'] = false;
|
|
}
|
|
|
|
return $item;
|
|
}
|
|
|
|
public function __construct() {
|
|
$this->register_scripts();
|
|
|
|
add_filter( 'elementor_pro/forms/field_types', [ $this, 'add_field_type' ] );
|
|
add_action( 'elementor_pro/forms/render_field/' . static::get_recaptcha_name(), [ $this, 'render_field' ], 10, 3 );
|
|
add_filter( 'elementor_pro/forms/render/item', [ $this, 'filter_field_item' ] );
|
|
add_filter( 'elementor_pro/editor/localize_settings', [ $this, 'localize_settings' ] );
|
|
|
|
if ( static::is_enabled() ) {
|
|
add_action( 'elementor_pro/forms/validation', [ $this, 'validation' ], 10, 2 );
|
|
add_action( 'elementor/preview/enqueue_scripts', [ $this, 'enqueue_scripts' ] );
|
|
}
|
|
|
|
if ( is_admin() ) {
|
|
add_action( 'elementor/admin/after_create_settings/' . Settings::PAGE_ID, [ $this, 'register_admin_fields' ] );
|
|
}
|
|
}
|
|
}
|