Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,5 @@ CONVERTKIT_API_SIGNED_SUBSCRIBER_ID=
CONVERTKIT_API_SIGNED_SUBSCRIBER_ID_NO_ACCESS=
CONVERTKIT_API_RECAPTCHA_SITE_KEY=
CONVERTKIT_API_RECAPTCHA_SECRET_KEY=
CONVERTKIT_API_CLOUDFLARE_TURNSTILE_SITE_KEY=
CONVERTKIT_API_CLOUDFLARE_TURNSTILE_SECRET_KEY=
4 changes: 4 additions & 0 deletions .github/workflows/_run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ jobs:
CONVERTKIT_API_SIGNED_SUBSCRIBER_ID_NO_ACCESS: ${{ secrets.CONVERTKIT_API_SIGNED_SUBSCRIBER_ID_NO_ACCESS }}
CONVERTKIT_API_RECAPTCHA_SITE_KEY: ${{ secrets.CONVERTKIT_API_RECAPTCHA_SITE_KEY }}
CONVERTKIT_API_RECAPTCHA_SECRET_KEY: ${{ secrets.CONVERTKIT_API_RECAPTCHA_SECRET_KEY }}
CONVERTKIT_API_CLOUDFLARE_TURNSTILE_SITE_KEY: ${{ secrets.CONVERTKIT_API_CLOUDFLARE_TURNSTILE_SITE_KEY }}
CONVERTKIT_API_CLOUDFLARE_TURNSTILE_SECRET_KEY: ${{ secrets.CONVERTKIT_API_CLOUDFLARE_TURNSTILE_SECRET_KEY }}

steps:
- name: Define Test Group Name
Expand Down Expand Up @@ -291,6 +293,8 @@ jobs:
CONVERTKIT_API_SIGNED_SUBSCRIBER_ID_NO_ACCESS=${{ env.CONVERTKIT_API_SIGNED_SUBSCRIBER_ID_NO_ACCESS }}
CONVERTKIT_API_RECAPTCHA_SITE_KEY=${{ env.CONVERTKIT_API_RECAPTCHA_SITE_KEY }}
CONVERTKIT_API_RECAPTCHA_SECRET_KEY=${{ env.CONVERTKIT_API_RECAPTCHA_SECRET_KEY }}
CONVERTKIT_API_CLOUDFLARE_TURNSTILE_SITE_KEY=${{ env.CONVERTKIT_API_CLOUDFLARE_TURNSTILE_SITE_KEY }}
CONVERTKIT_API_CLOUDFLARE_TURNSTILE_SECRET_KEY=${{ env.CONVERTKIT_API_CLOUDFLARE_TURNSTILE_SECRET_KEY }}
ENVEOF

# Installs wp-browser, Codeception, PHP CodeSniffer and anything else needed to run tests.
Expand Down
137 changes: 124 additions & 13 deletions admin/section/class-convertkit-admin-section-general.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,22 +59,22 @@ public function __construct() {

// Define settings sections.
$this->settings_sections = array(
'general' => array(
'general' => array(
'title' => $this->title,
'callback' => array( $this, 'print_section_info' ),
'wrap' => true,
),
'site-wide' => array(
'site-wide' => array(
'title' => __( 'Non-inline Forms', 'convertkit' ),
'callback' => array( $this, 'print_section_info_site_wide' ),
'wrap' => true,
),
'recaptcha' => array(
'title' => __( 'reCAPTCHA', 'convertkit' ),
'callback' => array( $this, 'print_section_info_recaptcha' ),
'spam-protection' => array(
'title' => __( 'Spam Protection', 'convertkit' ),
'callback' => array( $this, 'print_section_info_spam_protection' ),
'wrap' => true,
),
'advanced' => array(
'advanced' => array(
'title' => __( 'Advanced', 'convertkit' ),
'callback' => array( $this, 'print_section_info_advanced' ),
'wrap' => true,
Expand Down Expand Up @@ -409,15 +409,31 @@ public function register_fields() {
)
);

// Spam Protection.
add_settings_field(
'spam_protection_provider',
__( 'Provider', 'convertkit' ),
array( $this, 'spam_protection_provider_callback' ),
$this->settings_key,
$this->name . '-spam-protection',
array(
'label_for' => 'spam_protection_provider',
'description' => array(
__( 'Select which spam protection service to use for the Member Content signup form and Form Builder block.', 'convertkit' ),
),
)
);

// reCAPTCHA.
add_settings_field(
'recaptcha_site_key',
__( 'reCAPTCHA: Site Key', 'convertkit' ),
array( $this, 'recaptcha_site_key_callback' ),
$this->settings_key,
$this->name . '-recaptcha',
$this->name . '-spam-protection',
array(
'label_for' => 'recaptcha_site_key',
'class' => 'convertkit-spam-protection-recaptcha',
'description' => array(
__( 'Enter your Google reCAPTCHA v3 Site Key. When specified, this will be used to reduce spam signups.', 'convertkit' ),
),
Expand All @@ -428,9 +444,10 @@ public function register_fields() {
__( 'reCAPTCHA: Secret Key', 'convertkit' ),
array( $this, 'recaptcha_secret_key_callback' ),
$this->settings_key,
$this->name . '-recaptcha',
$this->name . '-spam-protection',
array(
'label_for' => 'recaptcha_secret_key',
'class' => 'convertkit-spam-protection-recaptcha',
'description' => array(
__( 'Enter your Google reCAPTCHA v3 Secret Key. When specified, this will be used to reduce spam signups.', 'convertkit' ),
),
Expand All @@ -441,9 +458,10 @@ public function register_fields() {
__( 'reCAPTCHA: Minimum Score', 'convertkit' ),
array( $this, 'recaptcha_minimum_score_callback' ),
$this->settings_key,
$this->name . '-recaptcha',
$this->name . '-spam-protection',
array(
'label_for' => 'recaptcha_minimum_score',
'class' => 'convertkit-spam-protection-recaptcha',
'min' => 0,
'max' => 1,
'step' => 0.01,
Expand All @@ -453,6 +471,36 @@ public function register_fields() {
)
);

// Cloudflare Turnstile.
add_settings_field(
'cloudflare_turnstile_site_key',
__( 'Cloudflare Turnstile: Site Key', 'convertkit' ),
array( $this, 'cloudflare_turnstile_site_key_callback' ),
$this->settings_key,
$this->name . '-spam-protection',
array(
'label_for' => 'cloudflare_turnstile_site_key',
'class' => 'convertkit-spam-protection-cloudflare_turnstile',
'description' => array(
__( 'Enter your Cloudflare Turnstile Site Key. When specified, this will be used to reduce spam signups.', 'convertkit' ),
),
)
);
add_settings_field(
'cloudflare_turnstile_secret_key',
__( 'Cloudflare Turnstile: Secret Key', 'convertkit' ),
array( $this, 'cloudflare_turnstile_secret_key_callback' ),
$this->settings_key,
$this->name . '-spam-protection',
array(
'label_for' => 'cloudflare_turnstile_secret_key',
'class' => 'convertkit-spam-protection-cloudflare_turnstile',
'description' => array(
__( 'Enter your Cloudflare Turnstile Secret Key. When specified, this will be used to reduce spam signups.', 'convertkit' ),
),
)
);

// Advanced.
add_settings_field(
'debug',
Expand Down Expand Up @@ -547,13 +595,13 @@ public function print_section_info_site_wide() {
}

/**
* Prints help info for the recaptcha section of the settings screen.
* Prints help info for the spam protection section of the settings screen.
*
* @since 3.0.0
* @since 3.3.7
*/
public function print_section_info_recaptcha() {
public function print_section_info_spam_protection() {
?>
<p class="description"><?php esc_html_e( 'Configure reCAPTCHA to protect the Member Content signup form and Form Builder block from spam and abuse.', 'convertkit' ); ?></p>
<p class="description"><?php esc_html_e( 'Configure a spam protection service to protect the Member Content signup form and Form Builder block from spam and abuse. Choose a provider below, then enter the corresponding site and secret keys.', 'convertkit' ); ?></p>
<?php
}

Expand Down Expand Up @@ -919,6 +967,29 @@ public function non_inline_form_limit_per_session_callback( $args ) {

}

/**
* Renders the dropdown for choosing the active spam protection provider.
*
* @since 3.3.7
*
* @param array $args Setting field arguments (name,description).
*/
public function spam_protection_provider_callback( $args ) {

$this->output_select_field(
'spam_protection_provider',
esc_attr( $this->settings->spam_protection_provider() ),
array(
'recaptcha' => esc_html__( 'Google reCAPTCHA v3', 'convertkit' ),
'cloudflare_turnstile' => esc_html__( 'Cloudflare Turnstile', 'convertkit' ),
),
$args['description'],
array( 'convertkit-conditional-display' ),
array( 'data-conditional-class-prefix' => 'convertkit-spam-protection-' )
);

}

/**
* Renders the input for the reCAPTCHA Site Key setting.
*
Expand Down Expand Up @@ -985,6 +1056,46 @@ public function recaptcha_minimum_score_callback( $args ) {

}

/**
* Renders the input for the Cloudflare Turnstile Site Key setting.
*
* @since 3.3.7
*
* @param array $args Setting field arguments (name,description).
*/
public function cloudflare_turnstile_site_key_callback( $args ) {

$this->output_text_field(
'cloudflare_turnstile_site_key',
esc_attr( $this->settings->cloudflare_turnstile_site_key() ),
$args['description'],
array(
'widefat',
)
);

}

/**
* Renders the input for the Cloudflare Turnstile Secret Key setting.
*
* @since 3.3.7
*
* @param array $args Setting field arguments (name,description).
*/
public function cloudflare_turnstile_secret_key_callback( $args ) {

$this->output_text_field(
'cloudflare_turnstile_secret_key',
esc_attr( $this->settings->cloudflare_turnstile_secret_key() ),
$args['description'],
array(
'widefat',
)
);

}

/**
* Renders the input for the Debug setting.
*
Expand Down
34 changes: 15 additions & 19 deletions includes/blocks/class-convertkit-block-form-builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,11 @@ public function maybe_subscribe() {
return;
}

// Check reCAPTCHA.
$recaptcha = new ConvertKit_Recaptcha();
$recaptcha_response = $recaptcha->verify_recaptcha(
( isset( $_POST['g-recaptcha-response'] ) ? sanitize_text_field( wp_unslash( $_POST['g-recaptcha-response'] ) ) : '' ),
'convertkit_form_builder'
);
// Check spam protection.
$spam_protection = new ConvertKit_Spam_Protection();

// Bail if reCAPTCHA failed.
if ( is_wp_error( $recaptcha_response ) ) {
// Bail if spam protection failed.
if ( is_wp_error( $spam_protection->verify( 'convertkit_form_builder' ) ) ) {
return;
}

Expand Down Expand Up @@ -721,23 +717,23 @@ public function render_form_button( $block_content, $block ) {
$block_content
);

// Return the button if reCAPTCHA does not need to be used.
$settings = new ConvertKit_Settings();
if ( ! $settings->has_recaptcha_site_and_secret_keys() ) {
// Return the button if no spam protection provider is active.
$spam_protection = new ConvertKit_Spam_Protection();
$provider = $spam_protection->get_active_provider();
if ( ! $provider ) {
return $block_content;
}

// Enqueue reCAPTCHA JS.
$recaptcha = new ConvertKit_Recaptcha();
$recaptcha->enqueue_scripts();
// Enqueue the spam protection provider's JS.
$provider->enqueue_scripts();

// Add reCAPTCHA attributes to button.
// Parse the button's DOM.
$parser = new ConvertKit_HTML_Parser( $block_content );
$button = $parser->xpath->query( '//button' )->item( 0 );
$button->setAttribute( 'data-sitekey', esc_attr( $settings->recaptcha_site_key() ) ); // @phpstan-ignore-line
$button->setAttribute( 'data-callback', 'convertKitRecaptchaFormSubmit' ); // @phpstan-ignore-line
$button->setAttribute( 'data-action', 'convertkit_form_builder' ); // @phpstan-ignore-line
$button->setAttribute( 'class', trim( $button->getAttribute( 'class' ) . ' g-recaptcha' ) ); // @phpstan-ignore-line

// Attach the spam protection provider's attributes/elements to the form/button as necessary.
// $button is narrowed from DOMNode to DOMElement by the //button xpath expression above.
$provider->attach_to_form_button_dom( $parser, $button, 'convertkit_form_builder' ); // @phpstan-ignore-line

// Return button HTML.
return $parser->get_body_html();
Expand Down
Loading