Changed source root directory

This commit is contained in:
2026-03-05 16:30:11 +01:00
parent dc85447ee1
commit 538f85d7a2
5868 changed files with 749734 additions and 99 deletions

View File

@@ -0,0 +1,346 @@
<?php
/**
** A base module for [acceptance]
**/
/* form_tag handler */
add_action( 'wpcf7_init', 'wpcf7_add_form_tag_acceptance', 10, 0 );
function wpcf7_add_form_tag_acceptance() {
wpcf7_add_form_tag( 'acceptance',
'wpcf7_acceptance_form_tag_handler',
array(
'name-attr' => true,
'selectable-values' => true,
)
);
}
function wpcf7_acceptance_form_tag_handler( $tag ) {
if ( empty( $tag->name ) ) {
return '';
}
$validation_error = wpcf7_get_validation_error( $tag->name );
$class = wpcf7_form_controls_class( $tag->type );
if ( $validation_error ) {
$class .= ' wpcf7-not-valid';
}
if ( $tag->has_option( 'invert' ) ) {
$class .= ' invert';
}
if ( $tag->has_option( 'optional' ) ) {
$class .= ' optional';
}
$atts = array(
'class' => trim( $class ),
);
$item_atts = array(
'type' => 'checkbox',
'name' => $tag->name,
'value' => '1',
'tabindex' => $tag->get_option( 'tabindex', 'signed_int', true ),
'checked' => $tag->has_option( 'default:on' ),
'class' => $tag->get_class_option() ? $tag->get_class_option() : null,
'id' => $tag->get_id_option(),
);
if ( $validation_error ) {
$item_atts['aria-invalid'] = 'true';
$item_atts['aria-describedby'] = wpcf7_get_validation_error_reference(
$tag->name
);
} else {
$item_atts['aria-invalid'] = 'false';
}
$item_atts = wpcf7_format_atts( $item_atts );
$content = empty( $tag->content )
? (string) reset( $tag->values )
: $tag->content;
$content = trim( $content );
if ( $content ) {
if ( $tag->has_option( 'label_first' ) ) {
$html = sprintf(
'<span class="wpcf7-list-item-label">%2$s</span><input %1$s />',
$item_atts,
$content
);
} else {
$html = sprintf(
'<input %1$s /><span class="wpcf7-list-item-label">%2$s</span>',
$item_atts,
$content
);
}
$html = sprintf(
'<span class="wpcf7-list-item"><label>%s</label></span>',
$html
);
} else {
$html = sprintf(
'<span class="wpcf7-list-item"><input %1$s /></span>',
$item_atts
);
}
$html = sprintf(
'<span class="wpcf7-form-control-wrap" data-name="%1$s"><span %2$s>%3$s</span>%4$s</span>',
esc_attr( $tag->name ),
wpcf7_format_atts( $atts ),
$html,
$validation_error
);
return $html;
}
/* Validation filter */
add_filter(
'wpcf7_validate_acceptance',
'wpcf7_acceptance_validation_filter',
10, 2
);
function wpcf7_acceptance_validation_filter( $result, $tag ) {
if ( ! wpcf7_acceptance_as_validation() ) {
return $result;
}
if ( $tag->has_option( 'optional' ) ) {
return $result;
}
$value = wpcf7_superglobal_post( $tag->name ) ? 1 : 0;
$invert = $tag->has_option( 'invert' );
if (
$invert and $value or
! $invert and ! $value
) {
$result->invalidate( $tag, wpcf7_get_message( 'accept_terms' ) );
}
return $result;
}
/* Acceptance filter */
add_filter( 'wpcf7_acceptance', 'wpcf7_acceptance_filter', 10, 2 );
function wpcf7_acceptance_filter( $accepted, $submission ) {
$tags = wpcf7_scan_form_tags( array( 'type' => 'acceptance' ) );
foreach ( $tags as $tag ) {
if ( empty( $tag->name ) ) {
continue;
}
$value = wpcf7_superglobal_post( $tag->name ) ? 1 : 0;
$content = empty( $tag->content )
? (string) reset( $tag->values )
: $tag->content;
$content = trim( $content );
if ( $value and $content ) {
$submission->add_consent( $tag->name, $content );
}
if ( $tag->has_option( 'optional' ) ) {
continue;
}
$invert = $tag->has_option( 'invert' );
if (
$invert and $value or
! $invert and ! $value
) {
$accepted = false;
}
}
return $accepted;
}
add_filter(
'wpcf7_form_class_attr',
'wpcf7_acceptance_form_class_attr',
10, 1
);
function wpcf7_acceptance_form_class_attr( $class_attr ) {
if ( wpcf7_acceptance_as_validation() ) {
return $class_attr . ' wpcf7-acceptance-as-validation';
}
return $class_attr;
}
function wpcf7_acceptance_as_validation() {
if ( ! $contact_form = wpcf7_get_current_contact_form() ) {
return false;
}
return $contact_form->is_true( 'acceptance_as_validation' );
}
add_filter(
'wpcf7_mail_tag_replaced_acceptance',
'wpcf7_acceptance_mail_tag',
10, 4
);
function wpcf7_acceptance_mail_tag( $replaced, $submitted, $html, $mail_tag ) {
$form_tag = $mail_tag->corresponding_form_tag();
if ( ! $form_tag ) {
return $replaced;
}
if ( ! empty( $submitted ) ) {
$replaced = __( 'Consented', 'contact-form-7' );
} else {
$replaced = __( 'Not consented', 'contact-form-7' );
}
$content = empty( $form_tag->content )
? (string) reset( $form_tag->values )
: $form_tag->content;
if ( ! $html ) {
$content = wp_strip_all_tags( $content );
}
$content = trim( $content );
if ( $content ) {
$replaced = sprintf(
/* translators: 1: 'Consented' or 'Not consented', 2: conditions */
_x( '%1$s: %2$s', 'mail output for acceptance checkboxes', 'contact-form-7' ),
$replaced,
$content
);
}
return $replaced;
}
/* Tag generator */
add_action( 'wpcf7_admin_init', 'wpcf7_add_tag_generator_acceptance', 35, 0 );
function wpcf7_add_tag_generator_acceptance() {
$tag_generator = WPCF7_TagGenerator::get_instance();
$tag_generator->add( 'acceptance', __( 'acceptance', 'contact-form-7' ),
'wpcf7_tag_generator_acceptance',
array( 'version' => '2' )
);
}
function wpcf7_tag_generator_acceptance( $contact_form, $options ) {
$field_types = array(
'acceptance' => array(
'display_name' => __( 'Acceptance checkbox', 'contact-form-7' ),
'heading' => __( 'Acceptance checkbox form-tag generator', 'contact-form-7' ),
'description' => __( 'Generates a form-tag for an <a href="https://contactform7.com/acceptance-checkbox/">acceptance checkbox</a>.', 'contact-form-7' ),
),
);
$tgg = new WPCF7_TagGeneratorGenerator( $options['content'] );
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'header', array(
'class' => 'description-box',
) );
$formatter->append_start_tag( 'h3' );
$formatter->append_preformatted(
esc_html( $field_types['acceptance']['heading'] )
);
$formatter->end_tag( 'h3' );
$formatter->append_start_tag( 'p' );
$formatter->append_preformatted(
wp_kses_data( $field_types['acceptance']['description'] )
);
$formatter->end_tag( 'header' );
$formatter->append_start_tag( 'div', array(
'class' => 'control-box',
) );
$formatter->call_user_func( static function () use ( $tgg, $field_types ) {
$tgg->print( 'field_type', array(
'with_optional' => true,
'select_options' => array(
'acceptance' => $field_types['acceptance']['display_name'],
),
) );
$tgg->print( 'field_name' );
$tgg->print( 'class_attr' );
} );
$formatter->append_start_tag( 'fieldset' );
$formatter->append_start_tag( 'legend', array(
'id' => $tgg->ref( 'value-legend' ),
) );
$formatter->append_preformatted(
esc_html( __( 'Condition', 'contact-form-7' ) )
);
$formatter->end_tag( 'legend' );
$formatter->append_start_tag( 'input', array(
'type' => 'text',
'required' => true,
'value' => __( 'Put the condition for consent here.', 'contact-form-7' ),
'data-tag-part' => 'content',
'aria-labelledby' => $tgg->ref( 'value-legend' ),
) );
$formatter->end_tag( 'div' );
$formatter->append_start_tag( 'footer', array(
'class' => 'insert-box',
) );
$formatter->call_user_func( static function () use ( $tgg, $field_types ) {
$tgg->print( 'insert_box_content' );
$tgg->print( 'mail_tag_tip' );
} );
$formatter->print();
}

View File

@@ -0,0 +1,317 @@
<?php
/**
* The Akismet integration module
*
* @link https://akismet.com/development/api/
*/
wpcf7_include_module_file( 'akismet/service.php' );
add_action(
'wpcf7_init',
'wpcf7_akismet_register_service',
30, 0
);
/**
* Registers the Akismet service.
*/
function wpcf7_akismet_register_service() {
$integration = WPCF7_Integration::get_instance();
$integration->add_service( 'akismet',
WPCF7_Akismet::get_instance()
);
}
add_filter( 'wpcf7_spam', 'wpcf7_akismet', 10, 2 );
function wpcf7_akismet( $spam, $submission ) {
if ( $spam ) {
return $spam;
}
if ( ! wpcf7_akismet_is_available() ) {
return false;
}
if ( ! $params = wpcf7_akismet_submitted_params() ) {
return false;
}
$comment = array(
'comment_type' => 'contact-form',
'comment_author' => $params['author'],
'comment_author_email' => $params['author_email'],
'comment_author_url' => $params['author_url'],
'comment_content' => $params['content'],
'blog' => home_url(),
'blog_lang' => get_locale(),
'blog_charset' => get_option( 'blog_charset' ),
'user_ip' => $submission->get_meta( 'remote_ip' ),
'user_agent' => $submission->get_meta( 'user_agent' ),
'referrer' => wpcf7_superglobal_server( 'HTTP_REFERER' ),
);
$datetime = date_create_immutable(
'@' . $submission->get_meta( 'timestamp' )
);
if ( $datetime ) {
$comment['comment_date_gmt'] = $datetime->format( DATE_ATOM );
}
if ( $permalink = get_permalink() ) {
$comment['permalink'] = $permalink;
}
$server_vars = array_diff_key(
$_SERVER,
array_flip( array( 'HTTP_COOKIE', 'HTTP_COOKIE2', 'PHP_AUTH_PW' ) )
);
$comment = array_merge( $comment, $server_vars );
$comment = apply_filters( 'wpcf7_akismet_parameters', $comment );
if ( wpcf7_akismet_comment_check( $comment ) ) {
$spam = true;
$submission->add_spam_log( array(
'agent' => 'akismet',
'reason' => __( 'Akismet returns a spam response.', 'contact-form-7' ),
) );
} else {
$spam = false;
}
return $spam;
}
/**
* Returns true if Akismet is active and has a valid API key.
*/
function wpcf7_akismet_is_available() {
if ( is_callable( array( 'Akismet', 'get_api_key' ) ) ) {
return (bool) Akismet::get_api_key();
}
return false;
}
/**
* Returns an array of parameters based on the current form submission.
* Returns false if Akismet is not active on the contact form.
*/
function wpcf7_akismet_submitted_params() {
$akismet_tags = array_filter(
wpcf7_scan_form_tags(),
static function ( $tag ) {
$akismet_option = $tag->get_option( 'akismet',
'(author|author_email|author_url)',
true
);
return (bool) $akismet_option;
}
);
if ( ! $akismet_tags ) { // Akismet is not active on this contact form.
return false;
}
$params = array(
'author' => '',
'author_email' => '',
'author_url' => '',
'content' => '',
);
foreach ( (array) $_POST as $key => $val ) {
if ( str_starts_with( $key, '_wpcf7' ) or '_wpnonce' === $key ) {
continue;
}
$vals = array_filter(
wpcf7_array_flatten( $val ),
static function ( $val ) {
return '' !== trim( $val );
}
);
if ( empty( $vals ) ) {
continue;
}
if ( $tags = wpcf7_scan_form_tags( array( 'name' => $key ) ) ) {
$tag = $tags[0];
$akismet_option = $tag->get_option( 'akismet',
'(author|author_email|author_url)',
true
);
if ( 'author' === $akismet_option ) {
$params['author'] = sprintf(
'%s %s',
$params['author'],
implode( ' ', $vals )
);
continue;
}
if (
'author_email' === $akismet_option and
'' === $params['author_email']
) {
$params['author_email'] = $vals[0];
continue;
}
if (
'author_url' === $akismet_option and
'' === $params['author_url']
) {
$params['author_url'] = $vals[0];
continue;
}
$vals = array_filter(
$vals,
static function ( $val ) use ( $tag ) {
if (
wpcf7_form_tag_supports( $tag->type, 'selectable-values' ) and
in_array( $val, $tag->labels, true )
) {
return false;
} else {
return true;
}
}
);
}
if ( $vals ) {
$params['content'] .= "\n\n" . implode( ', ', $vals );
}
}
$params = array_map( 'trim', $params );
return $params;
}
/**
* Sends data to Akismet.
*
* @param array $comment Submission and environment data.
* @return bool True if Akismet called it spam, or false otherwise.
*/
function wpcf7_akismet_comment_check( $comment ) {
$spam = false;
$query_string = wpcf7_build_query( $comment );
if ( is_callable( array( 'Akismet', 'http_post' ) ) ) {
$response = Akismet::http_post( $query_string, 'comment-check' );
} else {
return $spam;
}
if ( 'true' === $response[1] ) {
$spam = true;
}
if ( $submission = WPCF7_Submission::get_instance() ) {
$submission->push( 'akismet', array(
'comment' => $comment,
'spam' => $spam,
) );
}
return apply_filters( 'wpcf7_akismet_comment_check', $spam, $comment );
}
add_filter( 'wpcf7_posted_data', 'wpcf7_akismet_posted_data', 10, 1 );
/**
* Removes Akismet-related properties from the posted data.
*
* This does not affect the $_POST variable itself.
*
* @link https://plugins.trac.wordpress.org/browser/akismet/tags/5.0/_inc/akismet-frontend.js
*/
function wpcf7_akismet_posted_data( $posted_data ) {
if ( wpcf7_akismet_is_available() ) {
$posted_data = array_diff_key(
$posted_data,
array(
'ak_bib' => '',
'ak_bfs' => '',
'ak_bkpc' => '',
'ak_bkp' => '',
'ak_bmc' => '',
'ak_bmcc' => '',
'ak_bmk' => '',
'ak_bck' => '',
'ak_bmmc' => '',
'ak_btmc' => '',
'ak_bsc' => '',
'ak_bte' => '',
'ak_btec' => '',
'ak_bmm' => '',
)
);
}
return $posted_data;
}
add_filter(
'wpcf7_default_template',
'wpcf7_akismet_default_template',
10, 2
);
function wpcf7_akismet_default_template( $template, $prop ) {
if ( ! wpcf7_akismet_is_available() ) {
return $template;
}
if ( 'form' === $prop ) {
$template = str_replace(
array(
'[text* your-name ',
'[email* your-email ',
),
array(
'[text* your-name akismet:author ',
'[email* your-email akismet:author_email ',
),
$template
);
$privacy_notice = sprintf( '%s %s',
__( 'This form uses Akismet to reduce spam.', 'contact-form-7' ),
wpcf7_link(
'https://akismet.com/privacy/',
__( 'Learn how your data is processed.', 'contact-form-7' ),
array(
'target' => '_blank',
'rel' => 'nofollow noopener',
)
)
);
$template .= "\n\n" . $privacy_notice;
}
return $template;
}

View File

@@ -0,0 +1,86 @@
<?php
if ( ! class_exists( 'WPCF7_Service' ) ) {
return;
}
class WPCF7_Akismet extends WPCF7_Service {
private static $instance;
public static function get_instance() {
if ( empty( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
public function get_title() {
return __( 'Akismet', 'contact-form-7' );
}
public function is_active() {
return wpcf7_akismet_is_available();
}
public function get_categories() {
return array( 'spam_protection' );
}
public function icon() {
}
public function link() {
echo wp_kses_data( wpcf7_link(
'https://akismet.com/',
'akismet.com'
) );
}
public function display( $action = '' ) {
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'p' );
$formatter->append_preformatted(
esc_html( __( 'CAPTCHAs are designed to distinguish spambots from humans, and are therefore helpless against human spammers. In contrast to CAPTCHAs, Akismet checks form submissions against the global database of spam; this means Akismet is a comprehensive solution against spam. This is why we consider Akismet to be the centerpiece of the spam prevention strategy.', 'contact-form-7' ) )
);
$formatter->end_tag( 'p' );
$formatter->append_start_tag( 'p' );
$formatter->append_start_tag( 'strong' );
$formatter->append_preformatted(
wpcf7_link(
__( 'https://contactform7.com/spam-filtering-with-akismet/', 'contact-form-7' ),
__( 'Spam filtering with Akismet', 'contact-form-7' )
)
);
$formatter->end_tag( 'p' );
if ( $this->is_active() ) {
$formatter->append_start_tag( 'p', array(
'class' => 'dashicons-before dashicons-yes',
) );
$formatter->append_preformatted(
esc_html( __( 'Akismet is active on this site.', 'contact-form-7' ) )
);
$formatter->end_tag( 'p' );
}
$formatter->print();
}
}

View File

@@ -0,0 +1,441 @@
<?php
/**
** A base module for [checkbox], [checkbox*], and [radio]
**/
/* form_tag handler */
add_action( 'wpcf7_init', 'wpcf7_add_form_tag_checkbox', 10, 0 );
function wpcf7_add_form_tag_checkbox() {
wpcf7_add_form_tag( array( 'checkbox', 'checkbox*', 'radio' ),
'wpcf7_checkbox_form_tag_handler',
array(
'name-attr' => true,
'selectable-values' => true,
'multiple-controls-container' => true,
)
);
}
function wpcf7_checkbox_form_tag_handler( $tag ) {
if ( empty( $tag->name ) ) {
return '';
}
$validation_error = wpcf7_get_validation_error( $tag->name );
$class = wpcf7_form_controls_class( $tag->type );
if ( $validation_error ) {
$class .= ' wpcf7-not-valid';
}
$label_first = $tag->has_option( 'label_first' );
$use_label_element = $tag->has_option( 'use_label_element' );
$exclusive = $tag->has_option( 'exclusive' );
$free_text = $tag->has_option( 'free_text' );
$multiple = false;
if ( 'checkbox' === $tag->basetype ) {
$multiple = ! $exclusive;
} else { // radio
$exclusive = false;
}
if ( $exclusive ) {
$class .= ' wpcf7-exclusive-checkbox';
}
$atts = array();
$atts['class'] = $tag->get_class_option( $class );
$atts['id'] = $tag->get_id_option();
if ( $validation_error ) {
$atts['aria-describedby'] = wpcf7_get_validation_error_reference(
$tag->name
);
}
$tabindex = $tag->get_option( 'tabindex', 'signed_int', true );
if ( false !== $tabindex ) {
$tabindex = (int) $tabindex;
}
$html = '';
$count = 0;
if ( $data = (array) $tag->get_data_option() ) {
if ( $free_text ) {
$tag->values = array_merge(
array_slice( $tag->values, 0, -1 ),
array_values( $data ),
array_slice( $tag->values, -1 )
);
$tag->labels = array_merge(
array_slice( $tag->labels, 0, -1 ),
array_values( $data ),
array_slice( $tag->labels, -1 )
);
} else {
$tag->values = array_merge( $tag->values, array_values( $data ) );
$tag->labels = array_merge( $tag->labels, array_values( $data ) );
}
}
$values = $tag->values;
$labels = $tag->labels;
$default_choice = $tag->get_default_option( null, array(
'multiple' => $multiple,
) );
$hangover = wpcf7_get_hangover( $tag->name, $multiple ? array() : '' );
foreach ( $values as $key => $value ) {
if ( $hangover ) {
$checked = in_array( $value, (array) $hangover, true );
} else {
$checked = in_array( $value, (array) $default_choice, true );
}
if ( isset( $labels[$key] ) ) {
$label = $labels[$key];
} else {
$label = $value;
}
$item_atts = array(
'type' => $tag->basetype,
'name' => $tag->name . ( $multiple ? '[]' : '' ),
'value' => $value,
'checked' => $checked,
'tabindex' => $tabindex,
);
$item_atts = wpcf7_format_atts( $item_atts );
if ( $label_first ) { // put label first, input last
$item = sprintf(
'<span class="wpcf7-list-item-label">%1$s</span><input %2$s />',
esc_html( $label ),
$item_atts
);
} else {
$item = sprintf(
'<input %2$s /><span class="wpcf7-list-item-label">%1$s</span>',
esc_html( $label ),
$item_atts
);
}
if ( $use_label_element ) {
$item = '<label>' . $item . '</label>';
}
if ( false !== $tabindex and 0 < $tabindex ) {
$tabindex += 1;
}
$class = 'wpcf7-list-item';
$count += 1;
if ( 1 === $count ) {
$class .= ' first';
}
if ( count( $values ) === $count ) { // last round
$class .= ' last';
if ( $free_text ) {
$free_text_name = sprintf( '_wpcf7_free_text_%s', $tag->name );
$free_text_atts = array(
'type' => 'text',
'name' => $free_text_name,
'class' => 'wpcf7-free-text',
'tabindex' => $tabindex,
);
if ( wpcf7_is_posted() ) {
$free_text_atts['value'] = wpcf7_superglobal_post( $free_text_name );
}
$item .= sprintf(
' <input %s />',
wpcf7_format_atts( $free_text_atts )
);
$class .= ' has-free-text';
}
}
$item = '<span class="' . esc_attr( $class ) . '">' . $item . '</span>';
$html .= $item;
}
$html = sprintf(
'<span class="wpcf7-form-control-wrap" data-name="%1$s"><span %2$s>%3$s</span>%4$s</span>',
esc_attr( $tag->name ),
wpcf7_format_atts( $atts ),
$html,
$validation_error
);
return $html;
}
add_action(
'wpcf7_swv_create_schema',
'wpcf7_swv_add_checkbox_rules',
10, 2
);
function wpcf7_swv_add_checkbox_rules( $schema, $contact_form ) {
$tags = $contact_form->scan_form_tags( array(
'basetype' => array( 'checkbox', 'radio' ),
) );
foreach ( $tags as $tag ) {
if ( $tag->is_required() or 'radio' === $tag->type ) {
$schema->add_rule(
wpcf7_swv_create_rule( 'required', array(
'field' => $tag->name,
'error' => wpcf7_get_message( 'invalid_required' ),
) )
);
}
if ( 'radio' === $tag->type or $tag->has_option( 'exclusive' ) ) {
$schema->add_rule(
wpcf7_swv_create_rule( 'maxitems', array(
'field' => $tag->name,
'threshold' => 1,
'error' => $contact_form->filter_message(
__( 'Too many items are selected.', 'contact-form-7' )
),
) )
);
}
}
}
add_action(
'wpcf7_swv_create_schema',
'wpcf7_swv_add_checkbox_enum_rules',
20, 2
);
function wpcf7_swv_add_checkbox_enum_rules( $schema, $contact_form ) {
$tags = $contact_form->scan_form_tags( array(
'basetype' => array( 'checkbox', 'radio' ),
) );
$values = array_reduce(
$tags,
function ( $values, $tag ) {
if ( $tag->has_option( 'free_text' ) ) {
$values[$tag->name] = 'free_text';
}
if (
isset( $values[$tag->name] ) and
! is_array( $values[$tag->name] ) // Maybe 'free_text'
) {
return $values;
}
if ( ! isset( $values[$tag->name] ) ) {
$values[$tag->name] = array();
}
$tag_values = array_merge(
(array) $tag->values,
(array) $tag->get_data_option()
);
$values[$tag->name] = array_merge(
$values[$tag->name],
$tag_values
);
return $values;
},
array()
);
foreach ( $values as $field => $field_values ) {
if ( ! is_array( $field_values ) ) { // Maybe 'free_text'
continue;
}
$field_values = array_map(
static function ( $value ) {
return html_entity_decode(
(string) $value,
ENT_QUOTES | ENT_HTML5,
'UTF-8'
);
},
$field_values
);
$field_values = array_filter(
array_unique( $field_values ),
static function ( $value ) {
return '' !== $value;
}
);
$schema->add_rule(
wpcf7_swv_create_rule( 'enum', array(
'field' => $field,
'accept' => array_values( $field_values ),
'error' => $contact_form->filter_message(
__( 'Undefined value was submitted through this field.', 'contact-form-7' )
),
) )
);
}
}
add_filter( 'wpcf7_posted_data_checkbox',
'wpcf7_posted_data_checkbox',
10, 3
);
add_filter( 'wpcf7_posted_data_checkbox*',
'wpcf7_posted_data_checkbox',
10, 3
);
add_filter( 'wpcf7_posted_data_radio',
'wpcf7_posted_data_checkbox',
10, 3
);
function wpcf7_posted_data_checkbox( $value, $value_orig, $form_tag ) {
if ( $form_tag->has_option( 'free_text' ) ) {
$value = (array) $value;
$free_text_name = sprintf( '_wpcf7_free_text_%s', $form_tag->name );
$free_text = wpcf7_superglobal_post( $free_text_name );
$last_val = array_pop( $value );
if ( isset( $last_val ) ) {
$last_val = sprintf( '%s %s', $last_val, $free_text );
$value[] = trim( $last_val );
}
}
return $value;
}
/* Tag generator */
add_action( 'wpcf7_admin_init',
'wpcf7_add_tag_generator_checkbox_and_radio', 30, 0 );
function wpcf7_add_tag_generator_checkbox_and_radio() {
$tag_generator = WPCF7_TagGenerator::get_instance();
$basetypes = array(
'checkbox' => __( 'checkboxes', 'contact-form-7' ),
'radio' => __( 'radio buttons', 'contact-form-7' ),
);
foreach ( $basetypes as $id => $title ) {
$tag_generator->add( $id, $title,
'wpcf7_tag_generator_checkbox',
array( 'version' => '2' )
);
}
}
function wpcf7_tag_generator_checkbox( $contact_form, $options ) {
$field_types = array(
'checkbox' => array(
'display_name' => __( 'Checkboxes', 'contact-form-7' ),
'heading' => __( 'Checkboxes form-tag generator', 'contact-form-7' ),
'description' => __( 'Generates a form-tag for a group of <a href="https://contactform7.com/checkboxes-radio-buttons-and-menus/">checkboxes</a>.', 'contact-form-7' ),
),
'radio' => array(
'display_name' => __( 'Radio buttons', 'contact-form-7' ),
'heading' => __( 'Radio buttons form-tag generator', 'contact-form-7' ),
'description' => __( 'Generates a form-tag for a group of <a href="https://contactform7.com/checkboxes-radio-buttons-and-menus/">radio buttons</a>.', 'contact-form-7' ),
),
);
$basetype = $options['id'];
if ( ! in_array( $basetype, array_keys( $field_types ), true ) ) {
$basetype = 'checkbox';
}
$tgg = new WPCF7_TagGeneratorGenerator( $options['content'] );
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'header', array(
'class' => 'description-box',
) );
$formatter->append_start_tag( 'h3' );
$formatter->append_preformatted(
esc_html( $field_types[$basetype]['heading'] )
);
$formatter->end_tag( 'h3' );
$formatter->append_start_tag( 'p' );
$formatter->append_preformatted(
wp_kses_data( $field_types[$basetype]['description'] )
);
$formatter->end_tag( 'header' );
$formatter->append_start_tag( 'div', array(
'class' => 'control-box',
) );
$formatter->call_user_func( static function () use ( $tgg, $field_types, $basetype ) {
$tgg->print( 'field_type', array(
'with_required' => 'checkbox' === $basetype,
'select_options' => array(
$basetype => $field_types[$basetype]['display_name'],
),
) );
$tgg->print( 'field_name' );
$tgg->print( 'class_attr' );
$tgg->print( 'selectable_values', array(
'use_label_element' => 'checked',
) );
} );
$formatter->end_tag( 'div' );
$formatter->append_start_tag( 'footer', array(
'class' => 'insert-box',
) );
$formatter->call_user_func( static function () use ( $tgg, $field_types ) {
$tgg->print( 'insert_box_content' );
$tgg->print( 'mail_tag_tip' );
} );
$formatter->print();
}

View File

@@ -0,0 +1,215 @@
<?php
/**
* Constant Contact module main file
*
* @link https://contactform7.com/constant-contact-integration/
*/
add_action(
'wpcf7_init',
'wpcf7_constant_contact_register_service',
120, 0
);
/**
* Registers the Constant Contact service.
*/
function wpcf7_constant_contact_register_service() {
$integration = WPCF7_Integration::get_instance();
$integration->add_service( 'constant_contact',
WPCF7_ConstantContact::get_instance()
);
}
/**
* The WPCF7_Service subclass for Constant Contact.
*/
class WPCF7_ConstantContact extends WPCF7_Service {
const service_name = 'constant_contact';
private static $instance;
protected $client_id = '';
protected $client_secret = '';
public static function get_instance() {
if ( empty( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
$option = (array) WPCF7::get_option( self::service_name );
$this->client_id = $option['client_id'] ?? '';
$this->client_secret = $option['client_secret'] ?? '';
}
protected function reset_data() {
WPCF7::update_option( self::service_name, array() );
}
public function get_title() {
return __( 'Constant Contact', 'contact-form-7' );
}
public function is_active() {
return $this->client_id || $this->client_secret;
}
public function get_categories() {
return array( 'email_marketing' );
}
public function icon() {
}
public function link() {
}
protected function menu_page_url( $args = '' ) {
$args = wp_parse_args( $args, array() );
$url = add_query_arg(
array( 'service' => self::service_name ),
menu_page_url( 'wpcf7-integration', false )
);
if ( ! empty( $args ) ) {
$url = add_query_arg( $args, $url );
}
return $url;
}
public function load( $action = '' ) {
if (
'setup' === $action and
'POST' === wpcf7_superglobal_server( 'REQUEST_METHOD' )
) {
check_admin_referer( 'wpcf7-constant-contact-setup' );
if ( wpcf7_superglobal_post( 'reset' ) ) {
$this->reset_data();
$message = 'reset';
}
wp_safe_redirect( $this->menu_page_url( array(
'action' => 'setup',
'message' => $message ?? '',
) ) );
exit();
}
}
public function admin_notice( $message = '' ) {
switch ( $message ) {
case 'reset':
wp_admin_notice(
__( 'API configuration cleared.', 'contact-form-7' ),
array( 'type' => 'success' )
);
break;
}
}
public function display( $action = '' ) {
$formatter = new WPCF7_HTMLFormatter( array(
'allowed_html' => array_merge( wpcf7_kses_allowed_html(), array(
'form' => array(
'action' => true,
'method' => true,
),
) ),
) );
$formatter->append_start_tag( 'p' );
$formatter->append_preformatted(
wpcf7_link(
__( 'https://contactform7.com/2024/02/02/we-end-the-constant-contact-integration/', 'contact-form-7' ),
__( 'The Constant Contact integration has been removed.', 'contact-form-7' )
)
);
$formatter->end_tag( 'p' );
if ( $this->is_active() ) {
$formatter->append_start_tag( 'form', array(
'method' => 'post',
'action' => esc_url( $this->menu_page_url( 'action=setup' ) ),
) );
$formatter->call_user_func( static function () {
wp_nonce_field( 'wpcf7-constant-contact-setup' );
} );
$formatter->append_start_tag( 'table', array(
'class' => 'form-table',
) );
$formatter->append_start_tag( 'tbody' );
$formatter->append_start_tag( 'tr' );
$formatter->append_start_tag( 'th', array(
'scope' => 'row',
) );
$formatter->append_start_tag( 'label', array(
'for' => 'client_id',
) );
$formatter->append_preformatted(
esc_html( __( 'API Key', 'contact-form-7' ) )
);
$formatter->end_tag( 'th' );
$formatter->append_start_tag( 'td' );
$formatter->append_preformatted( esc_html( $this->client_id ) );
$formatter->end_tag( 'tr' );
$formatter->append_start_tag( 'tr' );
$formatter->append_start_tag( 'th', array(
'scope' => 'row',
) );
$formatter->append_start_tag( 'label', array(
'for' => 'client_secret',
) );
$formatter->append_preformatted(
esc_html( __( 'App Secret', 'contact-form-7' ) )
);
$formatter->end_tag( 'th' );
$formatter->append_start_tag( 'td' );
$formatter->append_preformatted(
esc_html( wpcf7_mask_password( $this->client_secret, 4, 4 ) )
);
$formatter->end_tag( 'table' );
$formatter->call_user_func( function () {
submit_button(
_x( 'Remove Keys', 'API keys', 'contact-form-7' ),
'small', 'reset'
);
} );
}
$formatter->print();
}
}

View File

@@ -0,0 +1,69 @@
<?php
/**
** A base module for [count], Twitter-like character count
**/
/* form_tag handler */
add_action( 'wpcf7_init', 'wpcf7_add_form_tag_count', 10, 0 );
function wpcf7_add_form_tag_count() {
wpcf7_add_form_tag( 'count',
'wpcf7_count_form_tag_handler',
array(
'name-attr' => true,
'zero-controls-container' => true,
'not-for-mail' => true,
)
);
}
function wpcf7_count_form_tag_handler( $tag ) {
if ( empty( $tag->name ) ) {
return '';
}
$targets = wpcf7_scan_form_tags( array( 'name' => $tag->name ) );
$maxlength = $minlength = null;
while ( $targets ) {
$target = array_shift( $targets );
if ( 'count' !== $target->type ) {
$maxlength = $target->get_maxlength_option();
$minlength = $target->get_minlength_option();
break;
}
}
if ( $maxlength and $minlength
and $maxlength < $minlength ) {
$maxlength = $minlength = null;
}
if ( $tag->has_option( 'down' ) ) {
$value = (int) $maxlength;
$class = 'wpcf7-character-count down';
} else {
$value = '0';
$class = 'wpcf7-character-count up';
}
$atts = array();
$atts['id'] = $tag->get_id_option();
$atts['class'] = $tag->get_class_option( $class );
$atts['data-target-name'] = $tag->name;
$atts['data-starting-value'] = $value;
$atts['data-current-value'] = $value;
$atts['data-maximum-value'] = $maxlength;
$atts['data-minimum-value'] = $minlength;
$html = sprintf(
'<span %1$s>%2$s</span>',
wpcf7_format_atts( $atts ),
$value
);
return $html;
}

View File

@@ -0,0 +1,262 @@
<?php
/**
** A base module for the following types of tags:
** [date] and [date*] # Date
**/
/* form_tag handler */
add_action( 'wpcf7_init', 'wpcf7_add_form_tag_date', 10, 0 );
function wpcf7_add_form_tag_date() {
wpcf7_add_form_tag( array( 'date', 'date*' ),
'wpcf7_date_form_tag_handler',
array(
'name-attr' => true,
)
);
}
function wpcf7_date_form_tag_handler( $tag ) {
if ( empty( $tag->name ) ) {
return '';
}
$validation_error = wpcf7_get_validation_error( $tag->name );
$class = wpcf7_form_controls_class( $tag->type );
$class .= ' wpcf7-validates-as-date';
if ( $validation_error ) {
$class .= ' wpcf7-not-valid';
}
$atts = array();
$atts['class'] = $tag->get_class_option( $class );
$atts['id'] = $tag->get_id_option();
$atts['tabindex'] = $tag->get_option( 'tabindex', 'signed_int', true );
$atts['min'] = $tag->get_date_option( 'min' );
$atts['max'] = $tag->get_date_option( 'max' );
$atts['step'] = $tag->get_option( 'step', 'int', true );
$atts['readonly'] = $tag->has_option( 'readonly' );
$atts['autocomplete'] = $tag->get_autocomplete_option();
if ( $tag->is_required() ) {
$atts['aria-required'] = 'true';
}
if ( $validation_error ) {
$atts['aria-invalid'] = 'true';
$atts['aria-describedby'] = wpcf7_get_validation_error_reference(
$tag->name
);
} else {
$atts['aria-invalid'] = 'false';
}
$value = (string) reset( $tag->values );
if ( $tag->has_option( 'placeholder' ) or $tag->has_option( 'watermark' ) ) {
$atts['placeholder'] = $value;
$value = '';
}
$value = $tag->get_default_option( $value );
if ( $value ) {
$datetime_obj = date_create_immutable(
preg_replace( '/[_]+/', ' ', $value ),
wp_timezone()
);
if ( $datetime_obj ) {
$value = $datetime_obj->format( 'Y-m-d' );
}
}
$value = wpcf7_get_hangover( $tag->name, $value );
$atts['value'] = $value;
$atts['type'] = $tag->basetype;
$atts['name'] = $tag->name;
$html = sprintf(
'<span class="wpcf7-form-control-wrap" data-name="%1$s"><input %2$s />%3$s</span>',
esc_attr( $tag->name ),
wpcf7_format_atts( $atts ),
$validation_error
);
return $html;
}
add_action(
'wpcf7_swv_create_schema',
'wpcf7_swv_add_date_rules',
10, 2
);
function wpcf7_swv_add_date_rules( $schema, $contact_form ) {
$tags = $contact_form->scan_form_tags( array(
'basetype' => array( 'date' ),
) );
foreach ( $tags as $tag ) {
if ( $tag->is_required() ) {
$schema->add_rule(
wpcf7_swv_create_rule( 'required', array(
'field' => $tag->name,
'error' => wpcf7_get_message( 'invalid_required' ),
) )
);
}
$schema->add_rule(
wpcf7_swv_create_rule( 'date', array(
'field' => $tag->name,
'error' => wpcf7_get_message( 'invalid_date' ),
) )
);
$min = $tag->get_date_option( 'min' );
$max = $tag->get_date_option( 'max' );
if ( false !== $min ) {
$schema->add_rule(
wpcf7_swv_create_rule( 'mindate', array(
'field' => $tag->name,
'threshold' => $min,
'error' => wpcf7_get_message( 'date_too_early' ),
) )
);
}
if ( false !== $max ) {
$schema->add_rule(
wpcf7_swv_create_rule( 'maxdate', array(
'field' => $tag->name,
'threshold' => $max,
'error' => wpcf7_get_message( 'date_too_late' ),
) )
);
}
}
}
/* Messages */
add_filter( 'wpcf7_messages', 'wpcf7_date_messages', 10, 1 );
function wpcf7_date_messages( $messages ) {
return array_merge( $messages, array(
'invalid_date' => array(
'description' => __( 'Date format that the sender entered is invalid', 'contact-form-7' ),
'default' => __( 'Please enter a date in YYYY-MM-DD format.', 'contact-form-7' ),
),
'date_too_early' => array(
'description' => __( 'Date is earlier than minimum limit', 'contact-form-7' ),
'default' => __( 'This field has a too early date.', 'contact-form-7' ),
),
'date_too_late' => array(
'description' => __( 'Date is later than maximum limit', 'contact-form-7' ),
'default' => __( 'This field has a too late date.', 'contact-form-7' ),
),
) );
}
/* Tag generator */
add_action( 'wpcf7_admin_init', 'wpcf7_add_tag_generator_date', 19, 0 );
function wpcf7_add_tag_generator_date() {
$tag_generator = WPCF7_TagGenerator::get_instance();
$tag_generator->add( 'date', __( 'date', 'contact-form-7' ),
'wpcf7_tag_generator_date',
array( 'version' => '2' )
);
}
function wpcf7_tag_generator_date( $contact_form, $options ) {
$field_types = array(
'date' => array(
'display_name' => __( 'Date field', 'contact-form-7' ),
'heading' => __( 'Date field form-tag generator', 'contact-form-7' ),
'description' => __( 'Generates a form-tag for a <a href="https://contactform7.com/date-field/">date input field</a>.', 'contact-form-7' ),
),
);
$tgg = new WPCF7_TagGeneratorGenerator( $options['content'] );
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'header', array(
'class' => 'description-box',
) );
$formatter->append_start_tag( 'h3' );
$formatter->append_preformatted(
esc_html( $field_types['date']['heading'] )
);
$formatter->end_tag( 'h3' );
$formatter->append_start_tag( 'p' );
$formatter->append_preformatted(
wp_kses_data( $field_types['date']['description'] )
);
$formatter->end_tag( 'header' );
$formatter->append_start_tag( 'div', array(
'class' => 'control-box',
) );
$formatter->call_user_func( static function () use ( $tgg, $field_types ) {
$tgg->print( 'field_type', array(
'with_required' => true,
'select_options' => array(
'date' => $field_types['date']['display_name'],
),
) );
$tgg->print( 'field_name' );
$tgg->print( 'class_attr' );
$tgg->print( 'min_max', array(
'type' => 'date',
'title' => __( 'Range', 'contact-form-7' ),
'min_option' => 'min:',
'max_option' => 'max:',
) );
$tgg->print( 'default_value', array(
'type' => 'date',
'with_placeholder' => false,
) );
} );
$formatter->end_tag( 'div' );
$formatter->append_start_tag( 'footer', array(
'class' => 'insert-box',
) );
$formatter->call_user_func( static function () use ( $tgg, $field_types ) {
$tgg->print( 'insert_box_content' );
$tgg->print( 'mail_tag_tip' );
} );
$formatter->print();
}

View File

@@ -0,0 +1,91 @@
<?php
add_filter( 'wpcf7_spam', 'wpcf7_disallowed_list', 10, 2 );
function wpcf7_disallowed_list( $spam, $submission ) {
if ( $spam ) {
return $spam;
}
$target = wpcf7_array_flatten( $submission->get_posted_data() );
$target[] = $submission->get_meta( 'remote_ip' );
$target[] = $submission->get_meta( 'user_agent' );
$target = implode( "\n", $target );
$word = wpcf7_check_disallowed_list( $target );
$word = wpcf7_apply_filters_deprecated(
'wpcf7_submission_is_blacklisted',
array( $word, $submission ),
'5.3',
'wpcf7_submission_has_disallowed_words'
);
$word = apply_filters(
'wpcf7_submission_has_disallowed_words',
$word,
$submission
);
if ( $word ) {
if ( is_bool( $word ) ) {
$reason = __( 'Disallowed words are used.', 'contact-form-7' );
} else {
$reason = sprintf(
/* translators: %s: comma separated list of disallowed words */
__( 'Disallowed words (%s) are used.', 'contact-form-7' ),
implode( ', ', (array) $word )
);
}
$submission->add_spam_log( array(
'agent' => 'disallowed_list',
'reason' => $reason,
) );
}
$spam = (bool) $word;
return $spam;
}
function wpcf7_check_disallowed_list( $target ) {
$mod_keys = get_option( 'disallowed_keys' );
if ( is_scalar( $mod_keys ) ) {
$mod_keys = trim( $mod_keys );
} else {
$mod_keys = '';
}
if ( '' === $mod_keys ) {
return false;
}
foreach ( explode( "\n", $mod_keys ) as $word ) {
$word = trim( $word );
$length = strlen( $word );
if ( $length < 2 or 256 < $length ) {
continue;
}
$pattern = sprintf( '#%s#i', preg_quote( $word, '#' ) );
if ( preg_match( $pattern, $target ) ) {
return $word;
}
}
return false;
}
function wpcf7_blacklist_check( $target ) {
wpcf7_deprecated_function(
__FUNCTION__,
'5.3',
'wpcf7_check_disallowed_list'
);
return wpcf7_check_disallowed_list( $target );
}

View File

@@ -0,0 +1,42 @@
<?php
/**
* Double Opt-In Helper module
*
* @link https://contactform7.com/doi-helper/
*/
add_action( 'wpcf7_doi', 'wpcf7_doihelper_start_session', 10, 3 );
/**
* Starts a double opt-in session.
*/
function wpcf7_doihelper_start_session( $agent_name, $args, &$token ) {
if ( isset( $token ) ) {
return;
}
if ( ! function_exists( 'doihelper_start_session' ) ) {
return;
}
$submission = WPCF7_Submission::get_instance();
if ( ! $submission ) {
return;
}
$contact_form = $submission->get_contact_form();
$do_doi = apply_filters( 'wpcf7_do_doi',
! $contact_form->is_false( 'doi' ),
$agent_name,
$args
);
if ( ! $do_doi ) {
return;
}
$token = doihelper_start_session( $agent_name, $args );
}

View File

@@ -0,0 +1,287 @@
<?php
/**
** A base module for [file] and [file*]
**/
/* form_tag handler */
add_action( 'wpcf7_init', 'wpcf7_add_form_tag_file', 10, 0 );
function wpcf7_add_form_tag_file() {
wpcf7_add_form_tag( array( 'file', 'file*' ),
'wpcf7_file_form_tag_handler',
array(
'name-attr' => true,
'file-uploading' => true,
)
);
}
function wpcf7_file_form_tag_handler( $tag ) {
if ( empty( $tag->name ) ) {
return '';
}
$validation_error = wpcf7_get_validation_error( $tag->name );
$class = wpcf7_form_controls_class( $tag->type );
if ( $validation_error ) {
$class .= ' wpcf7-not-valid';
}
$atts = array();
$atts['size'] = $tag->get_size_option( '40' );
$atts['class'] = $tag->get_class_option( $class );
$atts['id'] = $tag->get_id_option();
$atts['capture'] = $tag->get_option( 'capture', '(user|environment)', true );
$atts['tabindex'] = $tag->get_option( 'tabindex', 'signed_int', true );
$atts['accept'] = wpcf7_acceptable_filetypes(
$tag->get_option( 'filetypes' ), 'attr'
);
if ( $tag->is_required() ) {
$atts['aria-required'] = 'true';
}
if ( $validation_error ) {
$atts['aria-invalid'] = 'true';
$atts['aria-describedby'] = wpcf7_get_validation_error_reference(
$tag->name
);
} else {
$atts['aria-invalid'] = 'false';
}
$atts['type'] = 'file';
$atts['name'] = $tag->name;
$html = sprintf(
'<span class="wpcf7-form-control-wrap" data-name="%1$s"><input %2$s />%3$s</span>',
esc_attr( $tag->name ),
wpcf7_format_atts( $atts ),
$validation_error
);
return $html;
}
add_action(
'wpcf7_swv_create_schema',
'wpcf7_swv_add_file_rules',
10, 2
);
function wpcf7_swv_add_file_rules( $schema, $contact_form ) {
$tags = $contact_form->scan_form_tags( array(
'basetype' => array( 'file' ),
) );
foreach ( $tags as $tag ) {
if ( $tag->is_required() ) {
$schema->add_rule(
wpcf7_swv_create_rule( 'requiredfile', array(
'field' => $tag->name,
'error' => wpcf7_get_message( 'invalid_required' ),
) )
);
}
$schema->add_rule(
wpcf7_swv_create_rule( 'file', array(
'field' => $tag->name,
'accept' => explode( ',', wpcf7_acceptable_filetypes(
$tag->get_option( 'filetypes' ), 'attr'
) ),
'error' => wpcf7_get_message( 'upload_file_type_invalid' ),
) )
);
$schema->add_rule(
wpcf7_swv_create_rule( 'maxfilesize', array(
'field' => $tag->name,
'threshold' => $tag->get_limit_option(),
'error' => wpcf7_get_message( 'upload_file_too_large' ),
) )
);
}
}
add_filter( 'wpcf7_mail_tag_replaced_file', 'wpcf7_file_mail_tag', 10, 4 );
add_filter( 'wpcf7_mail_tag_replaced_file*', 'wpcf7_file_mail_tag', 10, 4 );
function wpcf7_file_mail_tag( $replaced, $submitted, $html, $mail_tag ) {
$submission = WPCF7_Submission::get_instance();
$uploaded_files = $submission->uploaded_files();
$name = $mail_tag->field_name();
if ( ! empty( $uploaded_files[$name] ) ) {
$paths = (array) $uploaded_files[$name];
$paths = array_map( 'wp_basename', $paths );
$replaced = wpcf7_flat_join( $paths, array(
'separator' => wp_get_list_item_separator(),
) );
}
return $replaced;
}
/* Tag generator */
add_action( 'wpcf7_admin_init', 'wpcf7_add_tag_generator_file', 50, 0 );
function wpcf7_add_tag_generator_file() {
$tag_generator = WPCF7_TagGenerator::get_instance();
$tag_generator->add( 'file', __( 'file', 'contact-form-7' ),
'wpcf7_tag_generator_file',
array( 'version' => '2' )
);
}
function wpcf7_tag_generator_file( $contact_form, $options ) {
$field_types = array(
'file' => array(
'display_name' => __( 'File uploading field', 'contact-form-7' ),
'heading' => __( 'File uploading field form-tag generator', 'contact-form-7' ),
'description' => __( 'Generates a form-tag for a <a href="https://contactform7.com/file-uploading-and-attachment/">file uploading field</a>.', 'contact-form-7' ),
),
);
$tgg = new WPCF7_TagGeneratorGenerator( $options['content'] );
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'header', array(
'class' => 'description-box',
) );
$formatter->append_start_tag( 'h3' );
$formatter->append_preformatted(
esc_html( $field_types['file']['heading'] )
);
$formatter->end_tag( 'h3' );
$formatter->append_start_tag( 'p' );
$formatter->append_preformatted(
wp_kses_data( $field_types['file']['description'] )
);
$formatter->end_tag( 'header' );
$formatter->append_start_tag( 'div', array(
'class' => 'control-box',
) );
$formatter->call_user_func( static function () use ( $tgg, $field_types ) {
$tgg->print( 'field_type', array(
'with_required' => true,
'select_options' => array(
'file' => $field_types['file']['display_name'],
),
) );
$tgg->print( 'field_name' );
$tgg->print( 'class_attr' );
} );
$formatter->append_start_tag( 'fieldset' );
$formatter->append_start_tag( 'legend', array(
'id' => $tgg->ref( 'filetypes-option-legend' ),
) );
$formatter->append_preformatted(
esc_html( __( 'Acceptable file types', 'contact-form-7' ) )
);
$formatter->end_tag( 'legend' );
$formatter->append_start_tag( 'label' );
$formatter->append_start_tag( 'span', array(
'id' => $tgg->ref( 'filetypes-option-description' ),
) );
$formatter->append_preformatted(
esc_html( __( 'Pipe-separated file types list. You can use file extensions and MIME types.', 'contact-form-7' ) )
);
$formatter->end_tag( 'span' );
$formatter->append_start_tag( 'br' );
$formatter->append_start_tag( 'input', array(
'type' => 'text',
'pattern' => '[0-9a-z*\/\|]*',
'value' => 'audio/*|video/*|image/*',
'aria-labelledby' => $tgg->ref( 'filetypes-option-legend' ),
'aria-describedby' => $tgg->ref( 'filetypes-option-description' ),
'data-tag-part' => 'option',
'data-tag-option' => 'filetypes:',
) );
$formatter->end_tag( 'fieldset' );
$formatter->append_start_tag( 'fieldset' );
$formatter->append_start_tag( 'legend', array(
'id' => $tgg->ref( 'limit-option-legend' ),
) );
$formatter->append_preformatted(
esc_html( __( 'File size limit', 'contact-form-7' ) )
);
$formatter->end_tag( 'legend' );
$formatter->append_start_tag( 'label' );
$formatter->append_start_tag( 'span', array(
'id' => $tgg->ref( 'limit-option-description' ),
) );
$formatter->append_preformatted(
esc_html( __( 'In bytes. You can use kb and mb suffixes.', 'contact-form-7' ) )
);
$formatter->end_tag( 'span' );
$formatter->append_start_tag( 'br' );
$formatter->append_start_tag( 'input', array(
'type' => 'text',
'pattern' => '[1-9][0-9]*([kKmM]?[bB])?',
'value' => '1mb',
'aria-labelledby' => $tgg->ref( 'limit-option-legend' ),
'aria-describedby' => $tgg->ref( 'limit-option-description' ),
'data-tag-part' => 'option',
'data-tag-option' => 'limit:',
) );
$formatter->end_tag( 'fieldset' );
$formatter->end_tag( 'div' );
$formatter->append_start_tag( 'footer', array(
'class' => 'insert-box',
) );
$formatter->call_user_func( static function () use ( $tgg, $field_types ) {
$tgg->print( 'insert_box_content' );
$tgg->print( 'mail_tag_tip' );
} );
$formatter->print();
}

View File

@@ -0,0 +1,347 @@
<?php
/**
** Module for Flamingo plugin.
** http://wordpress.org/extend/plugins/flamingo/
**/
add_action( 'wpcf7_submit', 'wpcf7_flamingo_submit', 10, 2 );
function wpcf7_flamingo_submit( $contact_form, $result ) {
if (
! class_exists( 'Flamingo_Contact' ) or
! class_exists( 'Flamingo_Inbound_Message' )
) {
return;
}
if ( $contact_form->in_demo_mode() ) {
return;
}
$cases = (array) apply_filters( 'wpcf7_flamingo_submit_if',
array( 'spam', 'mail_sent', 'mail_failed' )
);
if (
empty( $result['status'] ) or
! in_array( $result['status'], $cases, true )
) {
return;
}
$submission = WPCF7_Submission::get_instance();
if ( ! $submission or ! $posted_data = $submission->get_posted_data() ) {
return;
}
if ( $submission->get_meta( 'do_not_store' ) ) {
return;
}
// Exclude do-not-store form-tag values.
$posted_data = array_filter(
$posted_data,
static function ( $name ) use ( $contact_form ) {
return ! $contact_form->scan_form_tags( array(
'name' => $name,
'feature' => 'do-not-store',
) );
},
ARRAY_FILTER_USE_KEY
);
$email = wpcf7_flamingo_get_value( 'email', $contact_form );
$name = wpcf7_flamingo_get_value( 'name', $contact_form );
$subject = wpcf7_flamingo_get_value( 'subject', $contact_form );
$meta = array();
$special_mail_tags = array( 'serial_number', 'remote_ip',
'user_agent', 'url', 'date', 'time', 'post_id', 'post_name',
'post_title', 'post_url', 'post_author', 'post_author_email',
'site_title', 'site_description', 'site_url', 'site_admin_email',
'user_login', 'user_email', 'user_display_name',
);
foreach ( $special_mail_tags as $smt ) {
$tagname = sprintf( '_%s', $smt );
$mail_tag = new WPCF7_MailTag(
sprintf( '[%s]', $tagname ),
$tagname,
''
);
$meta[$smt] = apply_filters( 'wpcf7_special_mail_tags', null,
$tagname, false, $mail_tag
);
}
$timestamp = $submission->get_meta( 'timestamp' );
if ( $timestamp and $datetime = date_create( '@' . $timestamp ) ) {
$datetime->setTimezone( wp_timezone() );
$last_contacted = $datetime->format( 'Y-m-d H:i:s' );
} else {
$last_contacted = '0000-00-00 00:00:00';
}
if ( 'mail_sent' === $result['status'] ) {
$flamingo_contact = Flamingo_Contact::add( array(
'email' => $email,
'name' => $name,
'last_contacted' => $last_contacted,
) );
}
$post_meta = get_post_meta( $contact_form->id(), '_flamingo', true );
$channel_id = isset( $post_meta['channel'] )
? (int) $post_meta['channel']
: wpcf7_flamingo_add_channel(
$contact_form->name(),
$contact_form->title()
);
if ( $channel_id ) {
if (
! isset( $post_meta['channel'] ) or
$post_meta['channel'] !== $channel_id
) {
$post_meta = empty( $post_meta ) ? array() : (array) $post_meta;
$post_meta = array_merge( $post_meta, array(
'channel' => $channel_id,
) );
update_post_meta( $contact_form->id(), '_flamingo', $post_meta );
}
$channel = get_term( $channel_id,
Flamingo_Inbound_Message::channel_taxonomy
);
if ( ! $channel or is_wp_error( $channel ) ) {
$channel = 'contact-form-7';
} else {
$channel = $channel->slug;
}
} else {
$channel = 'contact-form-7';
}
$args = array(
'channel' => $channel,
'status' => $submission->get_status(),
'subject' => $subject,
'from' => trim( sprintf( '%s <%s>', $name, $email ) ),
'from_name' => $name,
'from_email' => $email,
'fields' => $posted_data,
'meta' => $meta,
'akismet' => $submission->pull( 'akismet' ),
'spam' => ( 'spam' === $result['status'] ),
'consent' => $submission->collect_consent(),
'timestamp' => $timestamp,
'posted_data_hash' => $submission->get_posted_data_hash(),
);
if ( $args['spam'] ) {
$args['spam_log'] = $submission->get_spam_log();
}
$args['recaptcha'] = $submission->pull( 'recaptcha' );
$args = apply_filters( 'wpcf7_flamingo_inbound_message_parameters', $args );
$flamingo_inbound = Flamingo_Inbound_Message::add( $args );
if ( empty( $flamingo_contact ) ) {
$flamingo_contact_id = 0;
} elseif ( method_exists( $flamingo_contact, 'id' ) ) {
$flamingo_contact_id = $flamingo_contact->id();
} else {
$flamingo_contact_id = $flamingo_contact->id;
}
if ( empty( $flamingo_inbound ) ) {
$flamingo_inbound_id = 0;
} elseif ( method_exists( $flamingo_inbound, 'id' ) ) {
$flamingo_inbound_id = $flamingo_inbound->id();
} else {
$flamingo_inbound_id = $flamingo_inbound->id;
}
$result += array(
'flamingo_contact_id' => absint( $flamingo_contact_id ),
'flamingo_inbound_id' => absint( $flamingo_inbound_id ),
);
do_action( 'wpcf7_after_flamingo', $result );
}
function wpcf7_flamingo_get_value( $field, $contact_form ) {
if ( empty( $field ) or empty( $contact_form ) ) {
return false;
}
$value = '';
if ( in_array( $field, array( 'email', 'name', 'subject' ), true ) ) {
$template = $contact_form->pref( 'flamingo_' . $field );
if ( null === $template ) {
$template = sprintf( '[your-%s]', $field );
} else {
$template = trim( wpcf7_strip_quote( $template ) );
}
$value = wpcf7_mail_replace_tags( $template );
}
$value = apply_filters( 'wpcf7_flamingo_get_value', $value,
$field, $contact_form
);
return $value;
}
function wpcf7_flamingo_add_channel( $slug, $name = '' ) {
if ( ! class_exists( 'Flamingo_Inbound_Message' ) ) {
return false;
}
$parent = term_exists( 'contact-form-7',
Flamingo_Inbound_Message::channel_taxonomy
);
if ( ! $parent ) {
$parent = wp_insert_term( __( 'Contact Form 7', 'contact-form-7' ),
Flamingo_Inbound_Message::channel_taxonomy,
array( 'slug' => 'contact-form-7' )
);
if ( is_wp_error( $parent ) ) {
return false;
}
}
$parent = (int) $parent['term_id'];
if (
! is_taxonomy_hierarchical( Flamingo_Inbound_Message::channel_taxonomy )
) {
// backward compat for Flamingo 1.0.4 and lower
return $parent;
}
if ( empty( $name ) ) {
$name = $slug;
}
$channel = term_exists( $slug,
Flamingo_Inbound_Message::channel_taxonomy,
$parent
);
if ( ! $channel ) {
$channel = wp_insert_term( $name,
Flamingo_Inbound_Message::channel_taxonomy,
array( 'slug' => $slug, 'parent' => $parent )
);
if ( is_wp_error( $channel ) ) {
return false;
}
}
return (int) $channel['term_id'];
}
add_action( 'wpcf7_after_update', 'wpcf7_flamingo_update_channel', 10, 1 );
function wpcf7_flamingo_update_channel( $contact_form ) {
if ( ! class_exists( 'Flamingo_Inbound_Message' ) ) {
return false;
}
$post_meta = get_post_meta( $contact_form->id(), '_flamingo', true );
$channel = isset( $post_meta['channel'] )
? get_term( $post_meta['channel'],
Flamingo_Inbound_Message::channel_taxonomy
)
: get_term_by( 'slug', $contact_form->name(),
Flamingo_Inbound_Message::channel_taxonomy
);
if ( ! $channel or is_wp_error( $channel ) ) {
return;
}
if ( $channel->name !== wp_unslash( $contact_form->title() ) ) {
wp_update_term( $channel->term_id,
Flamingo_Inbound_Message::channel_taxonomy,
array(
'name' => $contact_form->title(),
'slug' => $contact_form->name(),
'parent' => $channel->parent,
)
);
}
}
add_filter( 'wpcf7_special_mail_tags', 'wpcf7_flamingo_serial_number', 10, 4 );
/**
* Returns output string of a special mail-tag.
*
* @param string $output The string to be output.
* @param string $name The tag name of the special mail-tag.
* @param bool $html Whether the mail-tag is used in an HTML content.
* @param WPCF7_MailTag $mail_tag An object representation of the mail-tag.
* @return string Output of the given special mail-tag.
*/
function wpcf7_flamingo_serial_number( $output, $name, $html, $mail_tag = null ) {
if ( ! $mail_tag instanceof WPCF7_MailTag ) {
wpcf7_doing_it_wrong(
sprintf( '%s()', __FUNCTION__ ),
__( 'The fourth parameter ($mail_tag) must be an instance of the WPCF7_MailTag class.', 'contact-form-7' ),
'5.2.2'
);
}
if ( '_serial_number' !== $name ) {
return $output;
}
if (
! class_exists( 'Flamingo_Inbound_Message' ) or
! method_exists( 'Flamingo_Inbound_Message', 'count' )
) {
return $output;
}
if ( ! $contact_form = WPCF7_ContactForm::get_current() ) {
return $output;
}
$serial_number = 0;
$post_meta = get_post_meta( $contact_form->id(), '_flamingo', true );
$channel_id = isset( $post_meta['channel'] )
? (int) $post_meta['channel']
: wpcf7_flamingo_add_channel(
$contact_form->name(), $contact_form->title()
);
if ( $channel_id ) {
$serial_number = 1 + Flamingo_Inbound_Message::count( array(
'channel_id' => $channel_id,
) );
}
return (string) $serial_number;
}

View File

@@ -0,0 +1,36 @@
<?php
add_action( 'wpcf7_init', 'wpcf7_add_form_tag_hidden', 10, 0 );
function wpcf7_add_form_tag_hidden() {
wpcf7_add_form_tag( 'hidden',
'wpcf7_hidden_form_tag_handler',
array(
'name-attr' => true,
'display-hidden' => true,
)
);
}
function wpcf7_hidden_form_tag_handler( $tag ) {
if ( empty( $tag->name ) ) {
return '';
}
$atts = array();
$class = wpcf7_form_controls_class( $tag->type );
$atts['class'] = $tag->get_class_option( $class );
$atts['id'] = $tag->get_id_option();
$value = (string) reset( $tag->values );
$value = $tag->get_default_option( $value );
$atts['value'] = $value;
$atts['type'] = 'hidden';
$atts['name'] = $tag->name;
$atts = wpcf7_format_atts( $atts );
$html = sprintf( '<input %s />', $atts );
return $html;
}

View File

@@ -0,0 +1,36 @@
<?php
/**
** Retrieve list data from the Listo plugin.
** Listo http://wordpress.org/plugins/listo/
**/
add_filter( 'wpcf7_form_tag_data_option', 'wpcf7_listo', 10, 3 );
function wpcf7_listo( $data, $options, $args ) {
if ( ! function_exists( 'listo' ) ) {
return $data;
}
$args = wp_parse_args( $args, array() );
if ( $contact_form = wpcf7_get_current_contact_form() ) {
$args['locale'] = $contact_form->locale();
}
foreach ( (array) $options as $option ) {
$option = explode( '.', $option );
$type = $option[0];
if ( isset( $option[1] ) ) {
$args['group'] = $option[1];
} else {
unset( $args['group'] );
}
if ( $list = listo( $type, $args ) ) {
$data = array_merge( (array) $data, $list );
}
}
return $data;
}

View File

@@ -0,0 +1,281 @@
<?php
/**
** A base module for the following types of tags:
** [number] and [number*] # Number
** [range] and [range*] # Range
**/
/* form_tag handler */
add_action( 'wpcf7_init', 'wpcf7_add_form_tag_number', 10, 0 );
function wpcf7_add_form_tag_number() {
wpcf7_add_form_tag( array( 'number', 'number*', 'range', 'range*' ),
'wpcf7_number_form_tag_handler',
array(
'name-attr' => true,
)
);
}
function wpcf7_number_form_tag_handler( $tag ) {
if ( empty( $tag->name ) ) {
return '';
}
$validation_error = wpcf7_get_validation_error( $tag->name );
$class = wpcf7_form_controls_class( $tag->type );
$class .= ' wpcf7-validates-as-number';
if ( $validation_error ) {
$class .= ' wpcf7-not-valid';
}
$atts = array();
$atts['class'] = $tag->get_class_option( $class );
$atts['id'] = $tag->get_id_option();
$atts['tabindex'] = $tag->get_option( 'tabindex', 'signed_int', true );
$atts['min'] = $tag->get_option( 'min', 'signed_num', true );
$atts['max'] = $tag->get_option( 'max', 'signed_num', true );
$atts['step'] = $tag->get_option( 'step', 'num', true );
$atts['readonly'] = $tag->has_option( 'readonly' );
$atts['autocomplete'] = $tag->get_autocomplete_option();
if ( $tag->is_required() ) {
$atts['aria-required'] = 'true';
}
if ( $validation_error ) {
$atts['aria-invalid'] = 'true';
$atts['aria-describedby'] = wpcf7_get_validation_error_reference(
$tag->name
);
} else {
$atts['aria-invalid'] = 'false';
}
$value = (string) reset( $tag->values );
if ( $tag->has_option( 'placeholder' ) or $tag->has_option( 'watermark' ) ) {
$atts['placeholder'] = $value;
$value = '';
}
$value = $tag->get_default_option( $value );
$value = wpcf7_get_hangover( $tag->name, $value );
$atts['value'] = $value;
if ( 'range' === $tag->basetype ) {
if ( ! wpcf7_is_number( $atts['min'] ) ) {
$atts['min'] = '0';
}
if ( ! wpcf7_is_number( $atts['max'] ) ) {
$atts['max'] = '100';
}
if ( '' === $atts['value'] ) {
if ( $atts['min'] < $atts['max'] ) {
$atts['value'] = ( $atts['min'] + $atts['max'] ) / 2;
} else {
$atts['value'] = $atts['min'];
}
}
}
$atts['type'] = $tag->basetype;
$atts['name'] = $tag->name;
$html = sprintf(
'<span class="wpcf7-form-control-wrap" data-name="%1$s"><input %2$s />%3$s</span>',
esc_attr( $tag->name ),
wpcf7_format_atts( $atts ),
$validation_error
);
return $html;
}
add_action(
'wpcf7_swv_create_schema',
'wpcf7_swv_add_number_rules',
10, 2
);
function wpcf7_swv_add_number_rules( $schema, $contact_form ) {
$tags = $contact_form->scan_form_tags( array(
'basetype' => array( 'number', 'range' ),
) );
foreach ( $tags as $tag ) {
if ( $tag->is_required() ) {
$schema->add_rule(
wpcf7_swv_create_rule( 'required', array(
'field' => $tag->name,
'error' => wpcf7_get_message( 'invalid_required' ),
) )
);
}
$schema->add_rule(
wpcf7_swv_create_rule( 'number', array(
'field' => $tag->name,
'error' => wpcf7_get_message( 'invalid_number' ),
) )
);
$min = $tag->get_option( 'min', 'signed_num', true );
$max = $tag->get_option( 'max', 'signed_num', true );
if ( 'range' === $tag->basetype ) {
if ( ! wpcf7_is_number( $min ) ) {
$min = '0';
}
if ( ! wpcf7_is_number( $max ) ) {
$max = '100';
}
}
if ( wpcf7_is_number( $min ) ) {
$schema->add_rule(
wpcf7_swv_create_rule( 'minnumber', array(
'field' => $tag->name,
'threshold' => $min,
'error' => wpcf7_get_message( 'number_too_small' ),
) )
);
}
if ( wpcf7_is_number( $max ) ) {
$schema->add_rule(
wpcf7_swv_create_rule( 'maxnumber', array(
'field' => $tag->name,
'threshold' => $max,
'error' => wpcf7_get_message( 'number_too_large' ),
) )
);
}
}
}
/* Messages */
add_filter( 'wpcf7_messages', 'wpcf7_number_messages', 10, 1 );
function wpcf7_number_messages( $messages ) {
return array_merge( $messages, array(
'invalid_number' => array(
'description' => __( 'Number format that the sender entered is invalid', 'contact-form-7' ),
'default' => __( 'Please enter a number.', 'contact-form-7' ),
),
'number_too_small' => array(
'description' => __( 'Number is smaller than minimum limit', 'contact-form-7' ),
'default' => __( 'This field has a too small number.', 'contact-form-7' ),
),
'number_too_large' => array(
'description' => __( 'Number is larger than maximum limit', 'contact-form-7' ),
'default' => __( 'This field has a too large number.', 'contact-form-7' ),
),
) );
}
/* Tag generator */
add_action( 'wpcf7_admin_init', 'wpcf7_add_tag_generator_number', 18, 0 );
function wpcf7_add_tag_generator_number() {
$tag_generator = WPCF7_TagGenerator::get_instance();
$tag_generator->add( 'number', __( 'number', 'contact-form-7' ),
'wpcf7_tag_generator_number',
array( 'version' => '2' )
);
}
function wpcf7_tag_generator_number( $contact_form, $options ) {
$field_types = array(
'number' => array(
'display_name' => __( 'Number field', 'contact-form-7' ),
'heading' => __( 'Number field form-tag generator', 'contact-form-7' ),
'description' => __( 'Generates a form-tag for a <a href="https://contactform7.com/number-fields/">number input field</a>.', 'contact-form-7' ),
),
);
$tgg = new WPCF7_TagGeneratorGenerator( $options['content'] );
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'header', array(
'class' => 'description-box',
) );
$formatter->append_start_tag( 'h3' );
$formatter->append_preformatted(
esc_html( $field_types['number']['heading'] )
);
$formatter->end_tag( 'h3' );
$formatter->append_start_tag( 'p' );
$formatter->append_preformatted(
wp_kses_data( $field_types['number']['description'] )
);
$formatter->end_tag( 'header' );
$formatter->append_start_tag( 'div', array(
'class' => 'control-box',
) );
$formatter->call_user_func( static function () use ( $tgg, $field_types ) {
$tgg->print( 'field_type', array(
'with_required' => true,
'select_options' => array(
'number' => __( 'Spinbox', 'contact-form-7' ),
'range' => __( 'Slider', 'contact-form-7' ),
),
) );
$tgg->print( 'field_name' );
$tgg->print( 'class_attr' );
$tgg->print( 'min_max', array(
'title' => __( 'Range', 'contact-form-7' ),
'min_option' => 'min:',
'max_option' => 'max:',
) );
$tgg->print( 'default_value', array(
'type' => 'number',
'with_placeholder' => false,
) );
} );
$formatter->end_tag( 'div' );
$formatter->append_start_tag( 'footer', array(
'class' => 'insert-box',
) );
$formatter->call_user_func( static function () use ( $tgg, $field_types ) {
$tgg->print( 'insert_box_content' );
$tgg->print( 'mail_tag_tip' );
} );
$formatter->print();
}

View File

@@ -0,0 +1,299 @@
<?php
/**
** A base module for [quiz]
**/
/* form_tag handler */
add_action( 'wpcf7_init', 'wpcf7_add_form_tag_quiz', 10, 0 );
function wpcf7_add_form_tag_quiz() {
wpcf7_add_form_tag( 'quiz',
'wpcf7_quiz_form_tag_handler',
array(
'name-attr' => true,
'do-not-store' => true,
'not-for-mail' => true,
)
);
}
function wpcf7_quiz_form_tag_handler( $tag ) {
if ( empty( $tag->name ) ) {
return '';
}
$validation_error = wpcf7_get_validation_error( $tag->name );
$class = wpcf7_form_controls_class( $tag->type );
if ( $validation_error ) {
$class .= ' wpcf7-not-valid';
}
$atts = array();
$atts['size'] = $tag->get_size_option( '40' );
$atts['maxlength'] = $tag->get_maxlength_option();
$atts['minlength'] = $tag->get_minlength_option();
if ( $atts['maxlength'] and $atts['minlength']
and $atts['maxlength'] < $atts['minlength'] ) {
unset( $atts['maxlength'], $atts['minlength'] );
}
$atts['class'] = $tag->get_class_option( $class );
$atts['id'] = $tag->get_id_option();
$atts['tabindex'] = $tag->get_option( 'tabindex', 'signed_int', true );
$atts['autocomplete'] = 'off';
$atts['aria-required'] = 'true';
if ( $validation_error ) {
$atts['aria-invalid'] = 'true';
$atts['aria-describedby'] = wpcf7_get_validation_error_reference(
$tag->name
);
} else {
$atts['aria-invalid'] = 'false';
}
$pipes = $tag->pipes;
if ( $pipes instanceof WPCF7_Pipes
and ! $pipes->zero() ) {
$pipe = $pipes->random_pipe();
$question = $pipe->before;
$answer = $pipe->after;
} else {
// default quiz
$question = '1+1=?';
$answer = '2';
}
$answer = wpcf7_canonicalize( $answer, array(
'strip_separators' => true,
) );
$atts['type'] = 'text';
$atts['name'] = $tag->name;
$html = sprintf(
'<span class="wpcf7-form-control-wrap" data-name="%1$s"><label><span class="wpcf7-quiz-label">%2$s</span> <input %3$s /></label><input type="hidden" name="_wpcf7_quiz_answer_%4$s" value="%5$s" />%6$s</span>',
esc_attr( $tag->name ),
esc_html( $question ),
wpcf7_format_atts( $atts ),
$tag->name,
wp_hash( $answer, 'wpcf7_quiz' ),
$validation_error
);
return $html;
}
/* Validation filter */
add_filter( 'wpcf7_validate_quiz', 'wpcf7_quiz_validation_filter', 10, 2 );
function wpcf7_quiz_validation_filter( $result, $tag ) {
$name = $tag->name;
$answer = wpcf7_superglobal_post( $name );
$answer = wpcf7_canonicalize( $answer, array(
'strip_separators' => true,
) );
$answer_hash = wp_hash( $answer, 'wpcf7_quiz' );
$expected_hash = wpcf7_superglobal_post( '_wpcf7_quiz_answer_' . $name );
if ( ! hash_equals( $expected_hash, $answer_hash ) ) {
$result->invalidate( $tag, wpcf7_get_message( 'quiz_answer_not_correct' ) );
}
return $result;
}
/* Ajax echo filter */
add_filter( 'wpcf7_refill_response', 'wpcf7_quiz_ajax_refill', 10, 1 );
add_filter( 'wpcf7_feedback_response', 'wpcf7_quiz_ajax_refill', 10, 1 );
function wpcf7_quiz_ajax_refill( $items ) {
if ( ! is_array( $items ) ) {
return $items;
}
$fes = wpcf7_scan_form_tags( array( 'type' => 'quiz' ) );
if ( empty( $fes ) ) {
return $items;
}
$refill = array();
foreach ( $fes as $fe ) {
$name = $fe['name'];
$pipes = $fe['pipes'];
if ( empty( $name ) ) {
continue;
}
if ( $pipes instanceof WPCF7_Pipes
and ! $pipes->zero() ) {
$pipe = $pipes->random_pipe();
$question = $pipe->before;
$answer = $pipe->after;
} else {
// default quiz
$question = '1+1=?';
$answer = '2';
}
$answer = wpcf7_canonicalize( $answer, array(
'strip_separators' => true,
) );
$refill[$name] = array( $question, wp_hash( $answer, 'wpcf7_quiz' ) );
}
if ( ! empty( $refill ) ) {
$items['quiz'] = $refill;
}
return $items;
}
/* Messages */
add_filter( 'wpcf7_messages', 'wpcf7_quiz_messages', 10, 1 );
function wpcf7_quiz_messages( $messages ) {
$messages = array_merge( $messages, array(
'quiz_answer_not_correct' => array(
'description' =>
__( "Sender does not enter the correct answer to the quiz", 'contact-form-7' ),
'default' =>
__( "The answer to the quiz is incorrect.", 'contact-form-7' ),
),
) );
return $messages;
}
/* Tag generator */
add_action( 'wpcf7_admin_init', 'wpcf7_add_tag_generator_quiz', 40, 0 );
function wpcf7_add_tag_generator_quiz() {
$tag_generator = WPCF7_TagGenerator::get_instance();
$tag_generator->add( 'quiz', __( 'quiz', 'contact-form-7' ),
'wpcf7_tag_generator_quiz',
array( 'version' => '2' )
);
}
function wpcf7_tag_generator_quiz( $contact_form, $options ) {
$field_types = array(
'quiz' => array(
'display_name' => __( 'Quiz', 'contact-form-7' ),
'heading' => __( 'Quiz form-tag generator', 'contact-form-7' ),
'description' => __( 'Generates a form-tag for a <a href="https://contactform7.com/quiz/">quiz</a>.', 'contact-form-7' ),
),
);
$tgg = new WPCF7_TagGeneratorGenerator( $options['content'] );
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'header', array(
'class' => 'description-box',
) );
$formatter->append_start_tag( 'h3' );
$formatter->append_preformatted(
esc_html( $field_types['quiz']['heading'] )
);
$formatter->end_tag( 'h3' );
$formatter->append_start_tag( 'p' );
$formatter->append_preformatted(
wp_kses_data( $field_types['quiz']['description'] )
);
$formatter->end_tag( 'header' );
$formatter->append_start_tag( 'div', array(
'class' => 'control-box',
) );
$formatter->call_user_func( static function () use ( $tgg, $field_types ) {
$tgg->print( 'field_type', array(
'select_options' => array(
'quiz' => $field_types['quiz']['display_name'],
),
) );
$tgg->print( 'field_name' );
$tgg->print( 'class_attr' );
} );
$formatter->append_start_tag( 'fieldset' );
$formatter->append_start_tag( 'legend', array(
'id' => $tgg->ref( 'selectable-values-legend' ),
) );
$formatter->append_preformatted(
esc_html( __( 'Questions and answers', 'contact-form-7' ) )
);
$formatter->end_tag( 'legend' );
$formatter->append_start_tag( 'span', array(
'id' => $tgg->ref( 'selectable-values-description' ),
) );
$formatter->append_preformatted(
esc_html( __( 'One pipe-separated question-answer pair (question|answer) per line.', 'contact-form-7' ) )
);
$formatter->end_tag( 'span' );
$formatter->append_start_tag( 'br' );
$formatter->append_start_tag( 'textarea', array(
'required' => true,
'data-tag-part' => 'value',
'aria-labelledby' => $tgg->ref( 'selectable-values-legend' ),
'aria-describedby' => $tgg->ref( 'selectable-values-description' ),
) );
$formatter->append_preformatted(
esc_html( __( 'The capital of Brazil? | Rio', 'contact-form-7' ) )
);
$formatter->end_tag( 'textarea' );
$formatter->end_tag( 'div' );
$formatter->append_start_tag( 'footer', array(
'class' => 'insert-box',
) );
$formatter->call_user_func( static function () use ( $tgg, $field_types ) {
$tgg->print( 'insert_box_content' );
} );
$formatter->print();
}

View File

@@ -0,0 +1,631 @@
<?php
/**
** A base module for [captchac] and [captchar]
**/
/* form_tag handler */
add_action( 'wpcf7_init', 'wpcf7_add_form_tag_captcha', 10, 0 );
function wpcf7_add_form_tag_captcha() {
// CAPTCHA-Challenge (image)
wpcf7_add_form_tag( 'captchac',
'wpcf7_captchac_form_tag_handler',
array(
'name-attr' => true,
'zero-controls-container' => true,
'not-for-mail' => true,
)
);
// CAPTCHA-Response (input)
wpcf7_add_form_tag( 'captchar',
'wpcf7_captchar_form_tag_handler',
array(
'name-attr' => true,
'do-not-store' => true,
'not-for-mail' => true,
)
);
}
function wpcf7_captchac_form_tag_handler( $tag ) {
if ( ! class_exists( 'ReallySimpleCaptcha' ) ) {
return wp_kses_data( sprintf(
/* translators: %s: URL to the Really Simple CAPTCHA plugin page */
__( '<strong>Warning:</strong> The <a href="%s">Really Simple CAPTCHA</a> plugin is not active.', 'contact-form-7' ),
'https://wordpress.org/plugins/really-simple-captcha/'
) );
}
if ( empty( $tag->name ) ) {
return '';
}
$class = wpcf7_form_controls_class( $tag->type );
$class .= ' wpcf7-captcha-' . str_replace( ':', '', $tag->name );
$atts = array();
$atts['class'] = $tag->get_class_option( $class );
$atts['id'] = $tag->get_id_option();
$op = array( // Default
'img_size' => array( 72, 24 ),
'base' => array( 6, 18 ),
'font_size' => 14,
'font_char_width' => 15,
);
$op = array_merge( $op, wpcf7_captchac_options( $tag->options ) );
if ( ! $filename = wpcf7_generate_captcha( $op ) ) {
return '';
}
if ( ! empty( $op['img_size'] ) ) {
if ( isset( $op['img_size'][0] ) ) {
$atts['width'] = $op['img_size'][0];
}
if ( isset( $op['img_size'][1] ) ) {
$atts['height'] = $op['img_size'][1];
}
}
$atts['alt'] = 'captcha';
$atts['src'] = wpcf7_captcha_url( $filename );
$atts = wpcf7_format_atts( $atts );
$prefix = substr( $filename, 0, strrpos( $filename, '.' ) );
$html = sprintf(
'<input type="hidden" name="%1$s" value="%2$s" /><img %3$s />',
esc_attr( sprintf( '_wpcf7_captcha_challenge_%s', $tag->name ) ),
esc_attr( $prefix ),
$atts
);
return $html;
}
function wpcf7_captchar_form_tag_handler( $tag ) {
if ( empty( $tag->name ) ) {
return '';
}
$validation_error = wpcf7_get_validation_error( $tag->name );
$class = wpcf7_form_controls_class( $tag->type );
if ( $validation_error ) {
$class .= ' wpcf7-not-valid';
}
$atts = array();
$atts['size'] = $tag->get_size_option( '40' );
$atts['maxlength'] = $tag->get_maxlength_option();
$atts['minlength'] = $tag->get_minlength_option();
if (
$atts['maxlength'] and
$atts['minlength'] and
$atts['maxlength'] < $atts['minlength']
) {
unset( $atts['maxlength'], $atts['minlength'] );
}
$atts['class'] = $tag->get_class_option( $class );
$atts['id'] = $tag->get_id_option();
$atts['tabindex'] = $tag->get_option( 'tabindex', 'signed_int', true );
$atts['autocomplete'] = 'off';
if ( $validation_error ) {
$atts['aria-invalid'] = 'true';
$atts['aria-describedby'] = wpcf7_get_validation_error_reference(
$tag->name
);
} else {
$atts['aria-invalid'] = 'false';
}
$value = (string) reset( $tag->values );
if ( wpcf7_is_posted() ) {
$value = '';
}
if (
$tag->has_option( 'placeholder' ) or
$tag->has_option( 'watermark' )
) {
$atts['placeholder'] = $value;
$value = '';
}
$atts['value'] = $value;
$atts['type'] = 'text';
$atts['name'] = $tag->name;
$html = sprintf(
'<span class="wpcf7-form-control-wrap" data-name="%1$s"><input %2$s />%3$s</span>',
esc_attr( $tag->name ),
wpcf7_format_atts( $atts ),
$validation_error
);
return $html;
}
/* Validation filter */
add_filter(
'wpcf7_validate_captchar',
'wpcf7_captcha_validation_filter',
10, 2
);
function wpcf7_captcha_validation_filter( $result, $tag ) {
$prefix = wpcf7_superglobal_post( '_wpcf7_captcha_challenge_' . $tag->name );
$response = wpcf7_canonicalize( wpcf7_superglobal_post( $tag->name ) );
if ( ! wpcf7_check_captcha( $prefix, $response ) ) {
$result->invalidate( $tag, wpcf7_get_message( 'captcha_not_match' ) );
}
wpcf7_remove_captcha( $prefix );
return $result;
}
/* Ajax echo filter */
add_filter( 'wpcf7_refill_response', 'wpcf7_captcha_ajax_refill', 10, 1 );
add_filter( 'wpcf7_feedback_response', 'wpcf7_captcha_ajax_refill', 10, 1 );
function wpcf7_captcha_ajax_refill( $items ) {
if ( ! is_array( $items ) ) {
return $items;
}
$tags = wpcf7_scan_form_tags( array( 'type' => 'captchac' ) );
if ( empty( $tags ) ) {
return $items;
}
$refill = array();
foreach ( $tags as $tag ) {
$name = $tag->name;
$options = $tag->options;
if ( empty( $name ) ) {
continue;
}
$op = wpcf7_captchac_options( $options );
if ( $filename = wpcf7_generate_captcha( $op ) ) {
$captcha_url = wpcf7_captcha_url( $filename );
$refill[$name] = $captcha_url;
}
}
if ( ! empty( $refill ) ) {
$items['captcha'] = $refill;
}
return $items;
}
/* Messages */
add_filter( 'wpcf7_messages', 'wpcf7_captcha_messages', 10, 1 );
function wpcf7_captcha_messages( $messages ) {
$messages = array_merge( $messages, array(
'captcha_not_match' => array(
'description' =>
__( 'The code that sender entered does not match the CAPTCHA', 'contact-form-7' ),
'default' =>
__( 'Your entered code is incorrect.', 'contact-form-7' ),
),
) );
return $messages;
}
/* Warning message */
add_action(
'wpcf7_admin_warnings',
'wpcf7_captcha_display_warning_message',
10, 3
);
function wpcf7_captcha_display_warning_message( $page, $action, $object ) {
if ( $object instanceof WPCF7_ContactForm ) {
$contact_form = $object;
} else {
return;
}
$has_tags = (bool) $contact_form->scan_form_tags(
array( 'type' => array( 'captchac' ) )
);
if ( ! $has_tags ) {
return;
}
if ( ! class_exists( 'ReallySimpleCaptcha' ) ) {
return;
}
$uploads_dir = wpcf7_captcha_tmp_dir();
wpcf7_init_captcha();
if ( ! is_dir( $uploads_dir ) or ! wp_is_writable( $uploads_dir ) ) {
wp_admin_notice(
sprintf(
/* translators: %s: Path to the temporary folder */
__( 'This contact form contains CAPTCHA fields, but the temporary folder for the files (%s) does not exist or is not writable. You can create the folder or change its permission manually.', 'contact-form-7' ),
$uploads_dir
),
array( 'type' => 'warning' )
);
}
if (
! function_exists( 'imagecreatetruecolor' ) or
! function_exists( 'imagettftext' )
) {
wp_admin_notice(
__( 'This contact form contains CAPTCHA fields, but the necessary libraries (GD and FreeType) are not available on your server.', 'contact-form-7' ),
array( 'type' => 'warning' )
);
}
}
/* CAPTCHA functions */
function wpcf7_init_captcha() {
static $captcha = null;
if ( $captcha ) {
return $captcha;
}
if ( class_exists( 'ReallySimpleCaptcha' ) ) {
$captcha = new ReallySimpleCaptcha();
} else {
return false;
}
$dir = trailingslashit( wpcf7_captcha_tmp_dir() );
$captcha->tmp_dir = $dir;
if ( is_callable( array( $captcha, 'make_tmp_dir' ) ) ) {
$result = $captcha->make_tmp_dir();
if ( ! $result ) {
return false;
}
return $captcha;
}
$result = wp_mkdir_p( $dir );
if ( ! $result ) {
return false;
}
$htaccess_file = path_join( $dir, '.htaccess' );
if ( file_exists( $htaccess_file ) ) {
list( $first_line_comment ) = (array) file(
$htaccess_file,
FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES
);
if ( '# Apache 2.4+' === $first_line_comment ) {
return $captcha;
}
}
$filesystem = WPCF7_Filesystem::get_instance();
$htaccess_body = '
# Apache 2.4+
<IfModule authz_core_module>
Require all denied
<FilesMatch "^\w+\.(jpe?g|gif|png)$">
Require all granted
</FilesMatch>
</IfModule>
# Apache 2.2
<IfModule !authz_core_module>
Order deny,allow
Deny from all
<FilesMatch "^\w+\.(jpe?g|gif|png)$">
Allow from all
</FilesMatch>
</IfModule>
';
$filesystem->put_contents( $htaccess_file, ltrim( $htaccess_body ) );
return $captcha;
}
/**
* Returns the directory path for Really Simple CAPTCHA files.
*
* @return string Directory path.
*/
function wpcf7_captcha_tmp_dir() {
if ( defined( 'WPCF7_CAPTCHA_TMP_DIR' ) ) {
$dir = path_join( WP_CONTENT_DIR, WPCF7_CAPTCHA_TMP_DIR );
wp_mkdir_p( $dir );
if ( wpcf7_is_file_path_in_content_dir( $dir ) ) {
return $dir;
}
}
$dir = path_join( wpcf7_upload_dir( 'dir' ), 'wpcf7_captcha' );
wp_mkdir_p( $dir );
return $dir;
}
function wpcf7_captcha_tmp_url() {
if ( defined( 'WPCF7_CAPTCHA_TMP_URL' ) ) {
return WPCF7_CAPTCHA_TMP_URL;
} else {
return path_join( wpcf7_upload_dir( 'url' ), 'wpcf7_captcha' );
}
}
function wpcf7_captcha_url( $filename ) {
$url = path_join( wpcf7_captcha_tmp_url(), $filename );
if ( is_ssl() and 'http:' === substr( $url, 0, 5 ) ) {
$url = 'https:' . substr( $url, 5 );
}
return apply_filters( 'wpcf7_captcha_url', sanitize_url( $url ) );
}
function wpcf7_generate_captcha( $options = null ) {
if ( ! $captcha = wpcf7_init_captcha() ) {
return false;
}
if (
! is_dir( $captcha->tmp_dir ) or
! wp_is_writable( $captcha->tmp_dir )
) {
return false;
}
$img_type = imagetypes();
if ( $img_type & IMG_PNG ) {
$captcha->img_type = 'png';
} elseif ( $img_type & IMG_GIF ) {
$captcha->img_type = 'gif';
} elseif ( $img_type & IMG_JPG ) {
$captcha->img_type = 'jpeg';
} else {
return false;
}
if ( is_array( $options ) ) {
if ( isset( $options['img_size'] ) ) {
$captcha->img_size = $options['img_size'];
}
if ( isset( $options['base'] ) ) {
$captcha->base = $options['base'];
}
if ( isset( $options['font_size'] ) ) {
$captcha->font_size = $options['font_size'];
}
if ( isset( $options['font_char_width'] ) ) {
$captcha->font_char_width = $options['font_char_width'];
}
if ( isset( $options['fg'] ) ) {
$captcha->fg = $options['fg'];
}
if ( isset( $options['bg'] ) ) {
$captcha->bg = $options['bg'];
}
}
$prefix = wp_rand();
$captcha_word = $captcha->generate_random_word();
return $captcha->generate_image( $prefix, $captcha_word );
}
function wpcf7_check_captcha( $prefix, $response ) {
if ( ! $captcha = wpcf7_init_captcha() ) {
return false;
}
return $captcha->check( $prefix, $response );
}
function wpcf7_remove_captcha( $prefix ) {
if ( ! $captcha = wpcf7_init_captcha() ) {
return false;
}
// Contact Form 7 generates $prefix with wp_rand()
if ( preg_match( '/[^0-9]/', $prefix ) ) {
return false;
}
$captcha->remove( $prefix );
}
add_action( 'shutdown', 'wpcf7_cleanup_captcha_files', 20, 0 );
function wpcf7_cleanup_captcha_files() {
if ( ! $captcha = wpcf7_init_captcha() ) {
return false;
}
if ( is_callable( array( $captcha, 'cleanup' ) ) ) {
return $captcha->cleanup();
}
$dir = trailingslashit( wpcf7_captcha_tmp_dir() );
if (
! is_dir( $dir ) or
! is_readable( $dir ) or
! wp_is_writable( $dir )
) {
return false;
}
$filesystem = WPCF7_Filesystem::get_instance();
if ( $handle = opendir( $dir ) ) {
while ( false !== ( $file = readdir( $handle ) ) ) {
if ( ! preg_match( '/^[0-9]+\.(php|txt|png|gif|jpeg)$/', $file ) ) {
continue;
}
$stat = stat( path_join( $dir, $file ) );
if ( $stat['mtime'] + HOUR_IN_SECONDS < time() ) {
$filesystem->delete( path_join( $dir, $file ) );
}
}
closedir( $handle );
}
}
function wpcf7_captchac_options( $options ) {
if ( ! is_array( $options ) ) {
return array();
}
$op = array();
$image_size_array = preg_grep( '%^size:[smlSML]$%', $options );
if ( $image_size = array_shift( $image_size_array ) ) {
preg_match( '%^size:([smlSML])$%', $image_size, $is_matches );
switch ( strtolower( $is_matches[1] ) ) {
case 's':
$op['img_size'] = array( 60, 20 );
$op['base'] = array( 6, 15 );
$op['font_size'] = 11;
$op['font_char_width'] = 13;
break;
case 'l':
$op['img_size'] = array( 84, 28 );
$op['base'] = array( 6, 20 );
$op['font_size'] = 17;
$op['font_char_width'] = 19;
break;
case 'm':
default:
$op['img_size'] = array( 72, 24 );
$op['base'] = array( 6, 18 );
$op['font_size'] = 14;
$op['font_char_width'] = 15;
}
}
$fg_color_array = preg_grep(
'%^fg:#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$%',
$options
);
if ( $fg_color = array_shift( $fg_color_array ) ) {
preg_match(
'%^fg:#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$%',
$fg_color,
$fc_matches
);
if ( 3 === strlen( $fc_matches[1] ) ) {
$r = substr( $fc_matches[1], 0, 1 );
$g = substr( $fc_matches[1], 1, 1 );
$b = substr( $fc_matches[1], 2, 1 );
$op['fg'] = array(
hexdec( $r . $r ),
hexdec( $g . $g ),
hexdec( $b . $b ),
);
} elseif ( 6 === strlen( $fc_matches[1] ) ) {
$r = substr( $fc_matches[1], 0, 2 );
$g = substr( $fc_matches[1], 2, 2 );
$b = substr( $fc_matches[1], 4, 2 );
$op['fg'] = array(
hexdec( $r ),
hexdec( $g ),
hexdec( $b ),
);
}
}
$bg_color_array = preg_grep(
'%^bg:#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$%',
$options
);
if ( $bg_color = array_shift( $bg_color_array ) ) {
preg_match(
'%^bg:#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$%',
$bg_color,
$bc_matches
);
if ( 3 === strlen( $bc_matches[1] ) ) {
$r = substr( $bc_matches[1], 0, 1 );
$g = substr( $bc_matches[1], 1, 1 );
$b = substr( $bc_matches[1], 2, 1 );
$op['bg'] = array(
hexdec( $r . $r ),
hexdec( $g . $g ),
hexdec( $b . $b ),
);
} elseif ( 6 === strlen( $bc_matches[1] ) ) {
$r = substr( $bc_matches[1], 0, 2 );
$g = substr( $bc_matches[1], 2, 2 );
$b = substr( $bc_matches[1], 4, 2 );
$op['bg'] = array(
hexdec( $r ),
hexdec( $g ),
hexdec( $b ),
);
}
}
return $op;
}

View File

@@ -0,0 +1,6 @@
<?php
return array(
'dependencies' => array(),
'version' => WPCF7_VERSION,
);

View File

@@ -0,0 +1 @@
document.addEventListener("DOMContentLoaded",(e=>{var t;wpcf7_recaptcha={...null!==(t=wpcf7_recaptcha)&&void 0!==t?t:{}};const c=wpcf7_recaptcha.sitekey,{homepage:n,contactform:a}=wpcf7_recaptcha.actions,o=e=>{const{action:t,func:n,params:a}=e;grecaptcha.execute(c,{action:t}).then((e=>{const c=new CustomEvent("wpcf7grecaptchaexecuted",{detail:{action:t,token:e}});document.dispatchEvent(c)})).then((()=>{"function"==typeof n&&n(...a)})).catch((e=>console.error(e)))};if(grecaptcha.ready((()=>{o({action:n})})),document.addEventListener("change",(e=>{o({action:a})})),"undefined"!=typeof wpcf7&&"function"==typeof wpcf7.submit){const e=wpcf7.submit;wpcf7.submit=(t,c={})=>{o({action:a,func:e,params:[t,c]})}}document.addEventListener("wpcf7grecaptchaexecuted",(e=>{const t=document.querySelectorAll('form.wpcf7-form input[name="_wpcf7_recaptcha_response"]');for(let c=0;c<t.length;c++)t[c].setAttribute("value",e.detail.token)}))}));

View File

@@ -0,0 +1,260 @@
<?php
/**
* reCAPTCHA module main file
*
* @link https://contactform7.com/recaptcha/
*/
wpcf7_include_module_file( 'recaptcha/service.php' );
add_action( 'wpcf7_init', 'wpcf7_recaptcha_register_service', 40, 0 );
/**
* Registers the reCAPTCHA service.
*/
function wpcf7_recaptcha_register_service() {
$integration = WPCF7_Integration::get_instance();
$integration->add_service( 'recaptcha',
WPCF7_RECAPTCHA::get_instance()
);
}
add_action(
'wp_enqueue_scripts',
'wpcf7_recaptcha_enqueue_scripts',
20, 0
);
/**
* Enqueues frontend scripts for reCAPTCHA.
*/
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_register_script( 'google-recaptcha',
add_query_arg(
array(
'render' => $service->get_sitekey(),
),
$url
),
array(),
'3.0',
array( 'in_footer' => true )
);
$assets = include wpcf7_plugin_path( 'modules/recaptcha/index.asset.php' );
$assets = wp_parse_args( $assets, array(
'dependencies' => array(),
'version' => WPCF7_VERSION,
) );
wp_register_script(
'wpcf7-recaptcha',
wpcf7_plugin_url( 'modules/recaptcha/index.js' ),
array_merge(
$assets['dependencies'],
array(
'google-recaptcha',
'wp-polyfill',
)
),
$assets['version'],
array( 'in_footer' => true )
);
wp_enqueue_script( 'wpcf7-recaptcha' );
$wpcf7_recaptcha_obj = array(
'sitekey' => $service->get_sitekey(),
'actions' => apply_filters( 'wpcf7_recaptcha_actions', array(
'homepage' => 'homepage',
'contactform' => 'contactform',
) ),
);
wp_add_inline_script( 'wpcf7-recaptcha',
sprintf(
'var wpcf7_recaptcha = %s;',
wp_json_encode( $wpcf7_recaptcha_obj, JSON_PRETTY_PRINT )
),
'before'
);
}
add_filter(
'wpcf7_form_hidden_fields',
'wpcf7_recaptcha_add_hidden_fields',
100, 1
);
/**
* Adds hidden form field for reCAPTCHA.
*/
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 );
/**
* Verifies reCAPTCHA token on the server side.
*/
function wpcf7_recaptcha_verify_response( $spam, $submission ) {
if ( $spam ) {
return $spam;
}
$service = WPCF7_RECAPTCHA::get_instance();
if ( ! $service->is_active() ) {
return $spam;
}
$token = wpcf7_superglobal_post( '_wpcf7_recaptcha_response' );
if ( $service->verify( $token ) ) { // Human
$spam = false;
} else { // Bot
$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(
/* translators: 1: value of reCAPTCHA score 2: value of reCAPTCHA threshold */
__( '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 );
/**
* Registers form-tag types for reCAPTCHA.
*/
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', // no output
array( 'display-block' => true )
);
}
add_action( 'wpcf7_upgrade', 'wpcf7_upgrade_recaptcha_v2_v3', 10, 2 );
/**
* Adds warnings for users upgrading from reCAPTCHA v2 to v3.
*/
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;
}
// Maybe v2 keys are used now. Warning necessary.
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 );
/**
* Adds filters and actions for warnings.
*/
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
);
}
/**
* Increments the admin menu counter for the Integration page.
*/
function wpcf7_admin_menu_change_notice_recaptcha_v2_v3( $counts ) {
$counts['wpcf7-integration'] += 1;
return $counts;
}
/**
* Prints warnings on the admin screen.
*/
function wpcf7_admin_warnings_recaptcha_v2_v3( $page, $action, $object ) {
if ( 'wpcf7-integration' !== $page ) {
return;
}
wp_admin_notice(
sprintf(
/* translators: %s: link labeled 'reCAPTCHA (v3)' */
__( 'API keys for reCAPTCHA v3 are different from those for v2; keys for v2 do not 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' )
)
),
array( 'type' => 'warning' )
);
}

View File

@@ -0,0 +1,403 @@
<?php
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( 'spam_protection' );
}
public function icon() {
}
public function link() {
echo wp_kses_data( 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() and $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() and $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';
if ( apply_filters( 'wpcf7_use_recaptcha_net', false ) ) {
$endpoint = 'https://www.recaptcha.net/recaptcha/api/siteverify';
}
$sitekey = $this->get_sitekey();
$secret = $this->get_secret( $sitekey );
$request = array(
'body' => array(
'secret' => $secret,
'response' => $token,
),
);
$response = wp_remote_post( sanitize_url( $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->push( 'recaptcha', array(
'version' => '3.0',
'threshold' => $threshold,
'response' => $response_body,
) );
}
return $is_human;
}
public function get_threshold() {
return apply_filters( 'wpcf7_recaptcha_threshold', 0.50 );
}
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' === wpcf7_superglobal_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 = wpcf7_superglobal_post( 'sitekey' );
$secret = wpcf7_superglobal_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 ) {
wp_admin_notice(
__( '<strong>Error:</strong> Invalid key values.', 'contact-form-7' ),
array( 'type' => 'error' )
);
}
if ( 'success' === $message ) {
wp_admin_notice(
__( 'Settings saved.', 'contact-form-7' ),
array( 'type' => 'success' )
);
}
}
public function display( $action = '' ) {
$formatter = new WPCF7_HTMLFormatter( array(
'allowed_html' => array_merge( wpcf7_kses_allowed_html(), array(
'form' => array(
'action' => true,
'method' => true,
),
) ),
) );
$formatter->append_start_tag( 'p' );
$formatter->append_preformatted(
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.', 'contact-form-7' ) )
);
$formatter->end_tag( 'p' );
$formatter->append_start_tag( 'p' );
$formatter->append_start_tag( 'strong' );
$formatter->append_preformatted(
wpcf7_link(
__( 'https://contactform7.com/recaptcha/', 'contact-form-7' ),
__( 'reCAPTCHA (v3)', 'contact-form-7' )
)
);
$formatter->end_tag( 'p' );
if ( $this->is_active() ) {
$formatter->append_start_tag( 'p', array(
'class' => 'dashicons-before dashicons-yes',
) );
$formatter->append_preformatted(
esc_html( __( 'reCAPTCHA is active on this site.', 'contact-form-7' ) )
);
$formatter->end_tag( 'p' );
}
if ( 'setup' === $action ) {
$formatter->call_user_func( function () {
$this->display_setup();
} );
} else {
$formatter->append_start_tag( 'p' );
$formatter->append_start_tag( 'a', array(
'href' => esc_url( $this->menu_page_url( 'action=setup' ) ),
'class' => 'button',
) );
$formatter->append_preformatted(
esc_html( __( 'Setup integration', 'contact-form-7' ) )
);
$formatter->end_tag( 'p' );
}
$formatter->print();
}
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() and $this->get_global_secret() ) {
// nothing
} else {
submit_button(
_x( 'Remove Keys', 'API keys', 'contact-form-7' ),
'small', 'reset'
);
}
} else {
submit_button( __( 'Save Changes', 'contact-form-7' ) );
}
?>
</form>
<?php
}
}

View File

@@ -0,0 +1,118 @@
<?php
/**
* Reflection module
*
* @link https://contactform7.com/reflection/
*/
add_action( 'wpcf7_init', 'wpcf7_add_form_tag_reflection', 10, 0 );
/**
* Registers reflection-related form-tag types.
*/
function wpcf7_add_form_tag_reflection() {
wpcf7_add_form_tag( 'reflection',
'wpcf7_reflection_form_tag_handler',
array(
'name-attr' => true,
'display-block' => true,
'not-for-mail' => true,
)
);
wpcf7_add_form_tag( 'output',
'wpcf7_output_form_tag_handler',
array(
'name-attr' => true,
'not-for-mail' => true,
)
);
}
/**
* The form-tag handler for the reflection type.
*/
function wpcf7_reflection_form_tag_handler( $tag ) {
if ( empty( $tag->name ) ) {
return '';
}
$values = $tag->values ? $tag->values : array( '' );
if ( ! wpcf7_get_validation_error( $tag->name ) ) {
$hangover = array_filter( (array) wpcf7_get_hangover( $tag->name ) );
if ( $hangover ) {
$values = $hangover;
}
}
$content = array_reduce(
$values,
static function ( $carry, $item ) use ( $tag ) {
$output_tag = sprintf(
'<output %1$s>%2$s</output>',
wpcf7_format_atts( array(
'name' => $tag->name,
'data-default' => $item,
) ),
( '' !== $item ) ? esc_html( $item ) : '&nbsp;'
);
return $carry . $output_tag;
},
''
);
$html = sprintf(
'<fieldset %1$s>%2$s</fieldset>',
wpcf7_format_atts( array(
'data-reflection-of' => $tag->name,
'class' => $tag->get_class_option(
wpcf7_form_controls_class( $tag->type )
),
'id' => $tag->get_id_option(),
) ),
$content
);
return $html;
}
/**
* The form-tag handler for the output type.
*/
function wpcf7_output_form_tag_handler( $tag ) {
if ( empty( $tag->name ) ) {
return '';
}
$value = (string) reset( $tag->values );
if ( ! wpcf7_get_validation_error( $tag->name ) ) {
$hangover = array_filter( (array) wpcf7_get_hangover( $tag->name ) );
if ( $hangover ) {
$value = (string) reset( $hangover );
}
}
$html = sprintf(
'<output %1$s>%2$s</output>',
wpcf7_format_atts( array(
'data-reflection-of' => $tag->name,
'data-default' => $value,
'name' => $tag->name,
'class' => $tag->get_class_option(
wpcf7_form_controls_class( $tag->type )
),
'id' => $tag->get_id_option(),
) ),
esc_html( $value )
);
return $html;
}

View File

@@ -0,0 +1,23 @@
<?php
/**
** A base module for [response]
**/
/* form_tag handler */
add_action( 'wpcf7_init', 'wpcf7_add_form_tag_response', 10, 0 );
function wpcf7_add_form_tag_response() {
wpcf7_add_form_tag( 'response',
'wpcf7_response_form_tag_handler',
array(
'display-block' => true,
)
);
}
function wpcf7_response_form_tag_handler( $tag ) {
if ( $contact_form = wpcf7_get_current_contact_form() ) {
return $contact_form->form_response_output();
}
}

View File

@@ -0,0 +1,301 @@
<?php
/**
** A base module for [select] and [select*]
**/
/* form_tag handler */
add_action( 'wpcf7_init', 'wpcf7_add_form_tag_select', 10, 0 );
function wpcf7_add_form_tag_select() {
wpcf7_add_form_tag( array( 'select', 'select*' ),
'wpcf7_select_form_tag_handler',
array(
'name-attr' => true,
'selectable-values' => true,
)
);
}
function wpcf7_select_form_tag_handler( $tag ) {
if ( empty( $tag->name ) ) {
return '';
}
$validation_error = wpcf7_get_validation_error( $tag->name );
$class = wpcf7_form_controls_class( $tag->type );
if ( $validation_error ) {
$class .= ' wpcf7-not-valid';
}
$atts = array();
$atts['class'] = $tag->get_class_option( $class );
$atts['id'] = $tag->get_id_option();
$atts['tabindex'] = $tag->get_option( 'tabindex', 'signed_int', true );
$atts['autocomplete'] = $tag->get_autocomplete_option();
if ( $tag->is_required() ) {
$atts['aria-required'] = 'true';
}
if ( $validation_error ) {
$atts['aria-invalid'] = 'true';
$atts['aria-describedby'] = wpcf7_get_validation_error_reference(
$tag->name
);
} else {
$atts['aria-invalid'] = 'false';
}
$multiple = $tag->has_option( 'multiple' );
$include_blank = $tag->has_option( 'include_blank' );
$first_as_label = $tag->has_option( 'first_as_label' );
if ( $tag->has_option( 'size' ) ) {
$size = $tag->get_option( 'size', 'int', true );
if ( $size ) {
$atts['size'] = $size;
} elseif ( $multiple ) {
$atts['size'] = 4;
} else {
$atts['size'] = 1;
}
}
if ( $data = (array) $tag->get_data_option() ) {
$tag->values = array_merge( $tag->values, array_values( $data ) );
$tag->labels = array_merge( $tag->labels, array_values( $data ) );
}
$values = $tag->values;
$labels = $tag->labels;
$default_choice = $tag->get_default_option( null, array(
'multiple' => $multiple,
) );
if ( $include_blank or empty( $values ) ) {
array_unshift(
$labels,
__( '&#8212;Please choose an option&#8212;', 'contact-form-7' )
);
array_unshift( $values, '' );
} elseif ( $first_as_label ) {
$values[0] = '';
}
$html = '';
$hangover = wpcf7_get_hangover( $tag->name );
foreach ( $values as $key => $value ) {
if ( $hangover ) {
$selected = in_array( $value, (array) $hangover, true );
} else {
$selected = in_array( $value, (array) $default_choice, true );
}
$item_atts = array(
'value' => $value,
'selected' => $selected,
);
$label = isset( $labels[$key] ) ? $labels[$key] : $value;
$html .= sprintf(
'<option %1$s>%2$s</option>',
wpcf7_format_atts( $item_atts ),
esc_html( $label )
);
}
$atts['multiple'] = (bool) $multiple;
$atts['name'] = $tag->name . ( $multiple ? '[]' : '' );
$html = sprintf(
'<span class="wpcf7-form-control-wrap" data-name="%1$s"><select %2$s>%3$s</select>%4$s</span>',
esc_attr( $tag->name ),
wpcf7_format_atts( $atts ),
$html,
$validation_error
);
return $html;
}
add_action(
'wpcf7_swv_create_schema',
'wpcf7_swv_add_select_rules',
10, 2
);
function wpcf7_swv_add_select_rules( $schema, $contact_form ) {
$tags = $contact_form->scan_form_tags( array(
'type' => array( 'select*' ),
) );
foreach ( $tags as $tag ) {
$schema->add_rule(
wpcf7_swv_create_rule( 'required', array(
'field' => $tag->name,
'error' => wpcf7_get_message( 'invalid_required' ),
) )
);
}
}
add_action(
'wpcf7_swv_create_schema',
'wpcf7_swv_add_select_enum_rules',
20, 2
);
function wpcf7_swv_add_select_enum_rules( $schema, $contact_form ) {
$tags = $contact_form->scan_form_tags( array(
'basetype' => array( 'select' ),
) );
$values = array_reduce(
$tags,
function ( $values, $tag ) {
if ( ! isset( $values[$tag->name] ) ) {
$values[$tag->name] = array();
}
$tag_values = array_merge(
(array) $tag->values,
(array) $tag->get_data_option()
);
if ( $tag->has_option( 'first_as_label' ) ) {
$tag_values = array_slice( $tag_values, 1 );
}
$values[$tag->name] = array_merge(
$values[$tag->name],
$tag_values
);
return $values;
},
array()
);
foreach ( $values as $field => $field_values ) {
$field_values = array_map(
static function ( $value ) {
return html_entity_decode(
(string) $value,
ENT_QUOTES | ENT_HTML5,
'UTF-8'
);
},
$field_values
);
$field_values = array_filter(
array_unique( $field_values ),
static function ( $value ) {
return '' !== $value;
}
);
$schema->add_rule(
wpcf7_swv_create_rule( 'enum', array(
'field' => $field,
'accept' => array_values( $field_values ),
'error' => $contact_form->filter_message(
__( 'Undefined value was submitted through this field.', 'contact-form-7' )
),
) )
);
}
}
/* Tag generator */
add_action( 'wpcf7_admin_init', 'wpcf7_add_tag_generator_menu', 25, 0 );
function wpcf7_add_tag_generator_menu() {
$tag_generator = WPCF7_TagGenerator::get_instance();
$tag_generator->add( 'menu', __( 'drop-down menu', 'contact-form-7' ),
'wpcf7_tag_generator_menu',
array( 'version' => '2' )
);
}
function wpcf7_tag_generator_menu( $contact_form, $options ) {
$field_types = array(
'select' => array(
'display_name' => __( 'Drop-down menu', 'contact-form-7' ),
'heading' => __( 'Drop-down menu form-tag generator', 'contact-form-7' ),
'description' => __( 'Generates a form-tag for a <a href="https://contactform7.com/checkboxes-radio-buttons-and-menus/">drop-down menu</a>.', 'contact-form-7' ),
),
);
$tgg = new WPCF7_TagGeneratorGenerator( $options['content'] );
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'header', array(
'class' => 'description-box',
) );
$formatter->append_start_tag( 'h3' );
$formatter->append_preformatted(
esc_html( $field_types['select']['heading'] )
);
$formatter->end_tag( 'h3' );
$formatter->append_start_tag( 'p' );
$formatter->append_preformatted(
wp_kses_data( $field_types['select']['description'] )
);
$formatter->end_tag( 'header' );
$formatter->append_start_tag( 'div', array(
'class' => 'control-box',
) );
$formatter->call_user_func( static function () use ( $tgg, $field_types ) {
$tgg->print( 'field_type', array(
'with_required' => true,
'select_options' => array(
'select' => $field_types['select']['display_name'],
),
) );
$tgg->print( 'field_name' );
$tgg->print( 'class_attr' );
$tgg->print( 'selectable_values', array(
'first_as_label' => true,
) );
} );
$formatter->end_tag( 'div' );
$formatter->append_start_tag( 'footer', array(
'class' => 'insert-box',
) );
$formatter->call_user_func( static function () use ( $tgg, $field_types ) {
$tgg->print( 'insert_box_content' );
$tgg->print( 'mail_tag_tip' );
} );
$formatter->print();
}

View File

@@ -0,0 +1,447 @@
<?php
add_filter(
'wpcf7_pre_construct_contact_form_properties',
'wpcf7_sendinblue_register_property',
10, 2
);
/**
* Registers the sendinblue contact form property.
*/
function wpcf7_sendinblue_register_property( $properties, $contact_form ) {
$service = WPCF7_Sendinblue::get_instance();
if ( $service->is_active() ) {
$properties += array(
'sendinblue' => array(),
);
}
return $properties;
}
add_action(
'wpcf7_save_contact_form',
'wpcf7_sendinblue_save_contact_form',
10, 3
);
/**
* Saves the sendinblue property value.
*/
function wpcf7_sendinblue_save_contact_form( $contact_form, $args, $context ) {
$service = WPCF7_Sendinblue::get_instance();
if ( ! $service->is_active() ) {
return;
}
$prop = wp_parse_args(
(array) wpcf7_superglobal_post( 'wpcf7-sendinblue', array() ),
array(
'enable_contact_list' => false,
'contact_lists' => array(),
'enable_transactional_email' => false,
'email_template' => 0,
)
);
$prop['contact_lists'] = array_map( 'absint', $prop['contact_lists'] );
$prop['email_template'] = absint( $prop['email_template'] );
$contact_form->set_properties( array(
'sendinblue' => $prop,
) );
}
add_filter(
'wpcf7_editor_panels',
'wpcf7_sendinblue_editor_panels',
10, 1
);
/**
* Builds the editor panel for the sendinblue property.
*/
function wpcf7_sendinblue_editor_panels( $panels ) {
$service = WPCF7_Sendinblue::get_instance();
if ( ! $service->is_active() ) {
return $panels;
}
$contact_form = WPCF7_ContactForm::get_current();
$prop = wp_parse_args(
$contact_form->prop( 'sendinblue' ),
array(
'enable_contact_list' => false,
'contact_lists' => array(),
'enable_transactional_email' => false,
'email_template' => 0,
)
);
$editor_panel = static function () use ( $prop, $service ) {
$description = sprintf(
esc_html(
/* translators: %s: link labeled 'Brevo integration' */
__( 'You can set up the Brevo integration here. For details, see %s.', 'contact-form-7' )
),
wpcf7_link(
__( 'https://contactform7.com/sendinblue-integration/', 'contact-form-7' ),
__( 'Brevo integration', 'contact-form-7' )
)
);
$lists = wpcf7_sendinblue_get_lists();
$templates = $service->get_templates();
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'h2' );
$formatter->append_preformatted(
esc_html( __( 'Brevo', 'contact-form-7' ) )
);
$formatter->end_tag( 'h2' );
$formatter->append_start_tag( 'fieldset' );
$formatter->append_start_tag( 'legend' );
$formatter->append_preformatted( $description );
$formatter->end_tag( 'legend' );
$formatter->append_start_tag( 'table', array(
'class' => 'form-table',
'role' => 'presentation',
) );
$formatter->append_start_tag( 'tbody' );
$formatter->append_start_tag( 'tr', array(
'class' => $prop['enable_contact_list'] ? '' : 'inactive',
) );
$formatter->append_start_tag( 'th', array(
'scope' => 'row',
) );
$formatter->append_preformatted(
esc_html( __( 'Contact lists', 'contact-form-7' ) )
);
$formatter->append_start_tag( 'td' );
$formatter->append_start_tag( 'fieldset' );
$formatter->append_start_tag( 'legend', array(
'class' => 'screen-reader-text',
) );
$formatter->append_preformatted(
esc_html( __( 'Contact lists', 'contact-form-7' ) )
);
$formatter->end_tag( 'legend' );
$formatter->append_start_tag( 'label', array(
'for' => 'wpcf7-sendinblue-enable-contact-list',
) );
$formatter->append_start_tag( 'input', array(
'type' => 'checkbox',
'name' => 'wpcf7-sendinblue[enable_contact_list]',
'id' => 'wpcf7-sendinblue-enable-contact-list',
'value' => '1',
'checked' => $prop['enable_contact_list'],
) );
$formatter->append_preformatted(
esc_html( __( 'Add form submitters to your contact lists', 'contact-form-7' ) )
);
$formatter->end_tag( 'tr' );
$formatter->append_start_tag( 'tr' );
$formatter->append_start_tag( 'th', array(
'scope' => 'row',
) );
$formatter->append_start_tag( 'td' );
$formatter->append_start_tag( 'fieldset' );
if ( $lists ) {
$formatter->append_start_tag( 'legend' );
$formatter->append_preformatted(
esc_html( __( 'Select lists to which contacts are added:', 'contact-form-7' ) )
);
$formatter->end_tag( 'legend' );
$formatter->append_start_tag( 'ul' );
foreach ( $lists as $list ) {
$formatter->append_start_tag( 'li' );
$formatter->append_start_tag( 'label' );
$formatter->append_start_tag( 'input', array(
'type' => 'checkbox',
'name' => 'wpcf7-sendinblue[contact_lists][]',
'value' => $list['id'],
'checked' => in_array( $list['id'], $prop['contact_lists'] ),
) );
$formatter->append_whitespace();
$formatter->append_preformatted( esc_html( $list['name'] ) );
$formatter->end_tag( 'li' );
}
$formatter->end_tag( 'ul' );
} else {
$formatter->append_start_tag( 'legend' );
$formatter->append_preformatted(
esc_html( __( 'You have no contact list yet.', 'contact-form-7' ) )
);
$formatter->end_tag( 'legend' );
}
$formatter->end_tag( 'fieldset' );
$formatter->append_start_tag( 'p' );
$formatter->append_start_tag( 'a', array(
'href' => 'https://my.sendinblue.com/lists',
'target' => '_blank',
'rel' => 'external noreferrer noopener',
) );
$formatter->append_preformatted(
esc_html( __( 'Manage your contact lists', 'contact-form-7' ) )
);
$formatter->append_whitespace();
$formatter->append_start_tag( 'span', array(
'class' => 'screen-reader-text',
) );
$formatter->append_preformatted(
esc_html( __( '(opens in a new tab)', 'contact-form-7' ) )
);
$formatter->end_tag( 'span' );
$formatter->append_start_tag( 'span', array(
'aria-hidden' => 'true',
'class' => 'dashicons dashicons-external',
) );
$formatter->end_tag( 'p' );
$formatter->end_tag( 'tr' );
$formatter->append_start_tag( 'tr', array(
'class' => $prop['enable_transactional_email'] ? '' : 'inactive',
) );
$formatter->append_start_tag( 'th', array(
'scope' => 'row',
) );
$formatter->append_preformatted(
esc_html( __( 'Welcome email', 'contact-form-7' ) )
);
$formatter->append_start_tag( 'td' );
$formatter->append_start_tag( 'fieldset' );
$formatter->append_start_tag( 'legend', array(
'class' => 'screen-reader-text',
) );
$formatter->append_preformatted(
esc_html( __( 'Welcome email', 'contact-form-7' ) )
);
$formatter->end_tag( 'legend' );
$formatter->append_start_tag( 'label', array(
'for' => 'wpcf7-sendinblue-enable-transactional-email',
) );
$formatter->append_start_tag( 'input', array(
'type' => 'checkbox',
'name' => 'wpcf7-sendinblue[enable_transactional_email]',
'id' => 'wpcf7-sendinblue-enable-transactional-email',
'value' => '1',
'checked' => $prop['enable_transactional_email'],
) );
$formatter->append_preformatted(
esc_html( __( 'Send a welcome email to new contacts', 'contact-form-7' ) )
);
$formatter->end_tag( 'fieldset' );
$formatter->end_tag( 'tr' );
$formatter->append_start_tag( 'tr' );
$formatter->append_start_tag( 'th', array(
'scope' => 'row',
) );
$formatter->append_start_tag( 'td' );
$formatter->append_start_tag( 'fieldset' );
if ( $templates ) {
$formatter->append_start_tag( 'legend' );
$formatter->append_preformatted(
esc_html( __( 'Select an email template:', 'contact-form-7' ) )
);
$formatter->end_tag( 'legend' );
$formatter->append_start_tag( 'select', array(
'name' => 'wpcf7-sendinblue[email_template]',
) );
$formatter->append_start_tag( 'option', array(
'value' => 0,
'selected' => 0 === $prop['email_template'],
) );
$formatter->append_preformatted(
esc_html( __( '&mdash; Select &mdash;', 'contact-form-7' ) )
);
$formatter->end_tag( 'option' );
foreach ( $templates as $template ) {
$formatter->append_start_tag( 'option', array(
'value' => $template['id'],
'selected' => $prop['email_template'] === $template['id'],
) );
$formatter->append_preformatted( esc_html( $template['name'] ) );
$formatter->end_tag( 'option' );
}
$formatter->end_tag( 'select' );
} else {
$formatter->append_start_tag( 'legend' );
$formatter->append_preformatted(
esc_html( __( 'You have no active email template yet.', 'contact-form-7' ) )
);
$formatter->end_tag( 'legend' );
}
$formatter->end_tag( 'fieldset' );
$formatter->append_start_tag( 'p' );
$formatter->append_start_tag( 'a', array(
'href' => 'https://my.sendinblue.com/camp/lists/template',
'target' => '_blank',
'rel' => 'external noreferrer noopener',
) );
$formatter->append_preformatted(
esc_html( __( 'Manage your email templates', 'contact-form-7' ) )
);
$formatter->append_whitespace();
$formatter->append_start_tag( 'span', array(
'class' => 'screen-reader-text',
) );
$formatter->append_preformatted(
esc_html( __( '(opens in a new tab)', 'contact-form-7' ) )
);
$formatter->end_tag( 'span' );
$formatter->append_start_tag( 'span', array(
'aria-hidden' => 'true',
'class' => 'dashicons dashicons-external',
) );
$formatter->end_tag( 'p' );
$formatter->end_tag( 'tr' );
$formatter->end_tag( 'table' );
$formatter->print();
};
$panels += array(
'sendinblue-panel' => array(
'title' => __( 'Brevo', 'contact-form-7' ),
'callback' => $editor_panel,
),
);
return $panels;
}
/**
* Retrieves contact lists from Brevo's database.
*/
function wpcf7_sendinblue_get_lists() {
static $lists = array();
$service = WPCF7_Sendinblue::get_instance();
if ( ! empty( $lists ) or ! $service->is_active() ) {
return $lists;
}
$limit = 50;
$offset = 0;
while ( count( $lists ) < $limit * 10 ) {
$lists_next = (array) $service->get_lists( array(
'limit' => $limit,
'offset' => $offset,
) );
if ( ! empty( $lists_next ) ) {
$lists = array_merge( $lists, $lists_next );
}
if ( count( $lists_next ) < $limit ) {
break;
}
$offset += $limit;
}
return $lists;
}

View File

@@ -0,0 +1,101 @@
<?php
/**
* Double Opt-In Helper-related functions
*
* @link https://contactform7.com/doi-helper/
*/
add_action(
'doihelper_init',
'wpcf7_sendinblue_doi_register_agent',
10, 0
);
/**
* Registers wpcf7_sendinblue as an agent.
*/
function wpcf7_sendinblue_doi_register_agent() {
if ( ! function_exists( 'doihelper_register_agent' ) ) {
return;
}
doihelper_register_agent( 'wpcf7_sendinblue', array(
'optin_callback' => apply_filters(
'wpcf7_sendinblue_doi_optin_callback',
'wpcf7_sendinblue_doi_default_optin_callback'
),
'email_callback' => apply_filters(
'wpcf7_sendinblue_doi_email_callback',
'wpcf7_sendinblue_doi_default_email_callback'
),
) );
}
/**
* Default optin_callback function.
*/
function wpcf7_sendinblue_doi_default_optin_callback( $properties ) {
$service = WPCF7_Sendinblue::get_instance();
if ( ! $service->is_active() ) {
return;
}
if ( ! empty( $properties['contact'] ) ) {
$contact_id = $service->create_contact( $properties['contact'] );
if ( $contact_id and ! empty( $properties['email'] ) ) {
$service->send_email( $properties['email'] );
}
}
}
/**
* Default email_callback function.
*/
function wpcf7_sendinblue_doi_default_email_callback( $args ) {
if ( ! isset( $args['token'] ) or ! isset( $args['email_to'] ) ) {
return;
}
$site_title = wp_specialchars_decode(
get_bloginfo( 'name' ),
ENT_QUOTES
);
$link = add_query_arg(
array( 'doitoken' => $args['token'] ),
home_url()
);
$to = $args['email_to'];
$subject = sprintf(
/* translators: %s: blog name */
__( 'Opt-in confirmation from %s', 'contact-form-7' ),
$site_title
);
$message = sprintf(
/* translators: 1: blog name, 2: confirmation link */
__( 'Hello,
This is a confirmation email sent from %1$s.
We have received your submission to our web form, according to which you have allowed us to add you to our contact list. But, the process has not yet been completed. To complete it, please click the following link.
%2$s
If it was not your intention, or if you have no idea why you received this message, please do not click on the link, and ignore this message. We will never collect or use your personal data without your clear consent.
Sincerely,
%1$s', 'contact-form-7' ),
$site_title,
$link
);
wp_mail( $to, $subject, $message );
}

View File

@@ -0,0 +1,247 @@
<?php
/**
* Brevo module main file
*
* @link https://contactform7.com/sendinblue-integration/
*/
wpcf7_include_module_file( 'sendinblue/service.php' );
wpcf7_include_module_file( 'sendinblue/contact-form-properties.php' );
wpcf7_include_module_file( 'sendinblue/doi.php' );
add_action( 'wpcf7_init', 'wpcf7_sendinblue_register_service', 10, 0 );
/**
* Registers the Sendinblue service.
*/
function wpcf7_sendinblue_register_service() {
$integration = WPCF7_Integration::get_instance();
$integration->add_service( 'sendinblue',
WPCF7_Sendinblue::get_instance()
);
}
add_action( 'wpcf7_submit', 'wpcf7_sendinblue_submit', 10, 2 );
/**
* Callback to the wpcf7_submit action hook. Creates a contact
* based on the submission.
*/
function wpcf7_sendinblue_submit( $contact_form, $result ) {
if ( $contact_form->in_demo_mode() ) {
return;
}
$service = WPCF7_Sendinblue::get_instance();
if ( ! $service->is_active() ) {
return;
}
if ( empty( $result['posted_data_hash'] ) ) {
return;
}
if ( empty( $result['status'] )
or ! in_array( $result['status'], array( 'mail_sent', 'mail_failed' ), true ) ) {
return;
}
$submission = WPCF7_Submission::get_instance();
$consented = true;
foreach ( $contact_form->scan_form_tags( 'feature=name-attr' ) as $tag ) {
if ( $tag->has_option( 'consent_for:sendinblue' )
and null == $submission->get_posted_data( $tag->name ) ) {
$consented = false;
break;
}
}
if ( ! $consented ) {
return;
}
$prop = wp_parse_args(
$contact_form->prop( 'sendinblue' ),
array(
'enable_contact_list' => false,
'contact_lists' => array(),
'enable_transactional_email' => false,
'email_template' => 0,
)
);
if ( ! $prop['enable_contact_list'] ) {
return;
}
$attributes = wpcf7_sendinblue_collect_parameters();
$params = array(
'contact' => array(),
'email' => array(),
);
if ( ! empty( $attributes['EMAIL'] ) or ! empty( $attributes['SMS'] ) ) {
$params['contact'] = apply_filters(
'wpcf7_sendinblue_contact_parameters',
array(
'email' => $attributes['EMAIL'],
'attributes' => (object) $attributes,
'listIds' => (array) $prop['contact_lists'],
'updateEnabled' => false,
)
);
}
if ( $prop['enable_transactional_email'] and $prop['email_template'] ) {
$first_name = isset( $attributes['FIRSTNAME'] )
? trim( $attributes['FIRSTNAME'] )
: '';
$last_name = isset( $attributes['LASTNAME'] )
? trim( $attributes['LASTNAME'] )
: '';
if ( $first_name or $last_name ) {
$email_to_name = sprintf(
/* translators: 1: first name, 2: last name */
_x( '%1$s %2$s', 'personal name', 'contact-form-7' ),
$first_name,
$last_name
);
} else {
$email_to_name = '';
}
$params['email'] = apply_filters(
'wpcf7_sendinblue_email_parameters',
array(
'templateId' => absint( $prop['email_template'] ),
'to' => array(
array(
'name' => $email_to_name,
'email' => $attributes['EMAIL'],
),
),
'params' => (object) $attributes,
'tags' => array( 'Contact Form 7' ),
)
);
}
if ( is_email( $attributes['EMAIL'] ) ) {
$token = null;
do_action_ref_array( 'wpcf7_doi', array(
'wpcf7_sendinblue',
array(
'email_to' => $attributes['EMAIL'],
'properties' => $params,
),
&$token,
) );
if ( isset( $token ) ) {
return;
}
}
if ( ! empty( $params['contact'] ) ) {
$contact_id = $service->create_contact( $params['contact'] );
if ( $contact_id and ! empty( $params['email'] ) ) {
$service->send_email( $params['email'] );
}
}
}
/**
* Collects parameters for Sendinblue contact data based on submission.
*
* @return array Sendinblue contact parameters.
*/
function wpcf7_sendinblue_collect_parameters() {
$params = array();
$submission = WPCF7_Submission::get_instance();
foreach ( (array) $submission->get_posted_data() as $name => $val ) {
$name = strtoupper( $name );
if ( 'YOUR-' === substr( $name, 0, 5 ) ) {
$name = substr( $name, 5 );
}
if ( $val ) {
$params += array(
$name => $val,
);
}
}
if ( isset( $params['SMS'] ) ) {
$sms = trim( implode( ' ', (array) $params['SMS'] ) );
$sms = preg_replace( '/[#*].*$/', '', $sms ); // Remove extension
$is_international = false ||
str_starts_with( $sms, '+' ) ||
str_starts_with( $sms, '00' );
if ( $is_international ) {
$sms = preg_replace( '/^[+0]+/', '', $sms );
}
$sms = preg_replace( '/[^0-9]/', '', $sms );
if ( $is_international and 6 < strlen( $sms ) and strlen( $sms ) < 16 ) {
$params['SMS'] = '+' . $sms;
} else { // Invalid telephone number
unset( $params['SMS'] );
}
}
if ( isset( $params['NAME'] ) ) {
$your_name = implode( ' ', (array) $params['NAME'] );
$your_name = explode( ' ', $your_name );
if ( ! isset( $params['LASTNAME'] ) ) {
$params['LASTNAME'] = implode(
' ',
array_slice( $your_name, 1 )
);
}
if ( ! isset( $params['FIRSTNAME'] ) ) {
$params['FIRSTNAME'] = implode(
' ',
array_slice( $your_name, 0, 1 )
);
}
}
$params = array_map(
function ( $param ) {
if ( is_array( $param ) ) {
$param = wpcf7_array_flatten( $param );
$param = reset( $param );
}
return $param;
},
$params
);
$params = apply_filters(
'wpcf7_sendinblue_collect_parameters',
$params
);
return $params;
}

View File

@@ -0,0 +1,427 @@
<?php
if ( ! class_exists( 'WPCF7_Service' ) ) {
return;
}
class WPCF7_Sendinblue extends WPCF7_Service {
use WPCF7_Sendinblue_API;
private static $instance;
private $api_key;
public static function get_instance() {
if ( empty( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
$option = WPCF7::get_option( 'sendinblue' );
if ( isset( $option['api_key'] ) ) {
$this->api_key = $option['api_key'];
}
}
public function get_title() {
return __( 'Brevo', 'contact-form-7' );
}
public function is_active() {
return (bool) $this->get_api_key();
}
public function get_api_key() {
return $this->api_key;
}
public function get_categories() {
return array( 'email_marketing' );
}
public function icon() {
}
public function link() {
echo wp_kses_data( wpcf7_link(
'https://get.brevo.com/wpcf7-integration',
'brevo.com'
) );
}
protected function log( $url, $request, $response ) {
wpcf7_log_remote_request( $url, $request, $response );
}
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' => 'sendinblue' ), $url );
if ( ! empty( $args ) ) {
$url = add_query_arg( $args, $url );
}
return $url;
}
protected function save_data() {
WPCF7::update_option( 'sendinblue', array(
'api_key' => $this->api_key,
) );
}
protected function reset_data() {
$this->api_key = null;
$this->save_data();
}
public function load( $action = '' ) {
if (
'setup' === $action and
'POST' === wpcf7_superglobal_server( 'REQUEST_METHOD' )
) {
check_admin_referer( 'wpcf7-sendinblue-setup' );
if ( wpcf7_superglobal_post( 'reset' ) ) {
$this->reset_data();
$redirect_to = $this->menu_page_url( 'action=setup' );
} else {
$this->api_key = wpcf7_superglobal_post( 'api_key' );
$confirmed = $this->confirm_key();
if ( true === $confirmed ) {
$redirect_to = $this->menu_page_url( array(
'message' => 'success',
) );
$this->save_data();
} elseif ( false === $confirmed ) {
$redirect_to = $this->menu_page_url( array(
'action' => 'setup',
'message' => 'unauthorized',
) );
} else {
$redirect_to = $this->menu_page_url( array(
'action' => 'setup',
'message' => 'invalid',
) );
}
}
wp_safe_redirect( $redirect_to );
exit();
}
}
public function admin_notice( $message = '' ) {
if ( 'unauthorized' === $message ) {
wp_admin_notice(
sprintf(
'<strong>%1$s</strong>: %2$s',
__( 'Error', 'contact-form-7' ),
__( 'You have not been authenticated. Make sure the provided API key is correct.', 'contact-form-7' )
),
array( 'type' => 'error' )
);
}
if ( 'invalid' === $message ) {
wp_admin_notice(
sprintf(
'<strong>%1$s</strong>: %2$s',
__( 'Error', 'contact-form-7' ),
__( 'Invalid key values.', 'contact-form-7' )
),
array( 'type' => 'error' )
);
}
if ( 'success' === $message ) {
wp_admin_notice(
__( 'Settings saved.', 'contact-form-7' ),
array( 'type' => 'success' )
);
}
}
public function display( $action = '' ) {
$formatter = new WPCF7_HTMLFormatter( array(
'allowed_html' => array_merge( wpcf7_kses_allowed_html(), array(
'form' => array(
'action' => true,
'method' => true,
),
) ),
) );
$formatter->append_start_tag( 'p' );
$formatter->append_preformatted(
esc_html( __( 'Store and organize your contacts while protecting user privacy on Brevo, the leading CRM & email marketing platform in Europe. Brevo offers unlimited contacts and advanced marketing features.', 'contact-form-7' ) )
);
$formatter->end_tag( 'p' );
$formatter->append_start_tag( 'p' );
$formatter->append_start_tag( 'strong' );
$formatter->append_preformatted(
wpcf7_link(
__( 'https://contactform7.com/sendinblue-integration/', 'contact-form-7' ),
__( 'Brevo integration', 'contact-form-7' )
)
);
$formatter->end_tag( 'p' );
if ( $this->is_active() ) {
$formatter->append_start_tag( 'p', array(
'class' => 'dashicons-before dashicons-yes',
) );
$formatter->append_preformatted(
esc_html( __( 'Brevo is active on this site.', 'contact-form-7' ) )
);
$formatter->end_tag( 'p' );
}
if ( 'setup' === $action ) {
$formatter->call_user_func( function () {
$this->display_setup();
} );
} else {
$formatter->append_start_tag( 'p' );
$formatter->append_start_tag( 'a', array(
'href' => esc_url( $this->menu_page_url( 'action=setup' ) ),
'class' => 'button',
) );
$formatter->append_preformatted(
esc_html( __( 'Setup integration', 'contact-form-7' ) )
);
$formatter->end_tag( 'p' );
}
$formatter->print();
}
private function display_setup() {
$api_key = $this->get_api_key();
?>
<form method="post" action="<?php echo esc_url( $this->menu_page_url( 'action=setup' ) ); ?>">
<?php wp_nonce_field( 'wpcf7-sendinblue-setup' ); ?>
<table class="form-table">
<tbody>
<tr>
<th scope="row"><label for="publishable"><?php echo esc_html( __( 'API key', 'contact-form-7' ) ); ?></label></th>
<td><?php
if ( $this->is_active() ) {
echo esc_html( wpcf7_mask_password( $api_key, 4, 8 ) );
echo sprintf(
'<input type="hidden" value="%s" id="api_key" name="api_key" />',
esc_attr( $api_key )
);
} else {
echo sprintf(
'<input type="text" aria-required="true" value="%s" id="api_key" name="api_key" class="regular-text code" />',
esc_attr( $api_key )
);
}
?></td>
</tr>
</tbody>
</table>
<?php
if ( $this->is_active() ) {
submit_button(
_x( 'Remove key', 'API keys', 'contact-form-7' ),
'small', 'reset'
);
} else {
submit_button( __( 'Save changes', 'contact-form-7' ) );
}
?>
</form>
<?php
}
}
/**
* Trait for the Sendinblue API (v3).
*
* @link https://developers.sendinblue.com/reference
*/
trait WPCF7_Sendinblue_API {
public function confirm_key() {
$endpoint = 'https://api.sendinblue.com/v3/account';
$request = array(
'headers' => array(
'Accept' => 'application/json',
'Content-Type' => 'application/json; charset=utf-8',
'API-Key' => $this->get_api_key(),
),
);
$response = wp_remote_get( $endpoint, $request );
$response_code = (int) wp_remote_retrieve_response_code( $response );
if ( 200 === $response_code ) { // 200 OK
return true;
} elseif ( 401 === $response_code ) { // 401 Unauthorized
return false;
} elseif ( 400 <= $response_code ) {
if ( WP_DEBUG ) {
$this->log( $endpoint, $request, $response );
}
}
}
public function get_lists( $options = '' ) {
$options = wp_parse_args( $options, array(
'limit' => 50,
'offset' => 0,
) );
$endpoint = add_query_arg(
$options,
'https://api.sendinblue.com/v3/contacts/lists'
);
$request = array(
'headers' => array(
'Accept' => 'application/json',
'Content-Type' => 'application/json; charset=utf-8',
'API-Key' => $this->get_api_key(),
),
);
$response = wp_remote_get( $endpoint, $request );
$response_code = (int) wp_remote_retrieve_response_code( $response );
if ( 200 === $response_code ) { // 200 OK
$response_body = wp_remote_retrieve_body( $response );
$response_body = json_decode( $response_body, true );
if ( empty( $response_body['lists'] ) ) {
return array();
} else {
return (array) $response_body['lists'];
}
} elseif ( 400 <= $response_code ) {
if ( WP_DEBUG ) {
$this->log( $endpoint, $request, $response );
}
}
}
public function get_templates() {
$endpoint = add_query_arg(
array(
'templateStatus' => 'true',
'limit' => 100,
'offset' => 0,
),
'https://api.sendinblue.com/v3/smtp/templates'
);
$request = array(
'headers' => array(
'Accept' => 'application/json',
'Content-Type' => 'application/json; charset=utf-8',
'API-Key' => $this->get_api_key(),
),
);
$response = wp_remote_get( $endpoint, $request );
$response_code = (int) wp_remote_retrieve_response_code( $response );
if ( 200 === $response_code ) { // 200 OK
$response_body = wp_remote_retrieve_body( $response );
$response_body = json_decode( $response_body, true );
if ( empty( $response_body['templates'] ) ) {
return array();
} else {
return (array) $response_body['templates'];
}
} elseif ( 400 <= $response_code ) {
if ( WP_DEBUG ) {
$this->log( $endpoint, $request, $response );
}
}
}
public function create_contact( $properties ) {
$endpoint = 'https://api.sendinblue.com/v3/contacts';
$request = array(
'headers' => array(
'Accept' => 'application/json',
'Content-Type' => 'application/json; charset=utf-8',
'API-Key' => $this->get_api_key(),
),
'body' => wp_json_encode( $properties ),
);
$response = wp_remote_post( $endpoint, $request );
$response_code = (int) wp_remote_retrieve_response_code( $response );
if ( in_array( $response_code, array( 201, 204 ), true ) ) {
$contact_id = wp_remote_retrieve_body( $response );
return $contact_id;
} elseif ( 400 <= $response_code ) {
if ( WP_DEBUG ) {
$this->log( $endpoint, $request, $response );
}
}
return false;
}
public function send_email( $properties ) {
$endpoint = 'https://api.sendinblue.com/v3/smtp/email';
$request = array(
'headers' => array(
'Accept' => 'application/json',
'Content-Type' => 'application/json; charset=utf-8',
'API-Key' => $this->get_api_key(),
),
'body' => wp_json_encode( $properties ),
);
$response = wp_remote_post( $endpoint, $request );
$response_code = (int) wp_remote_retrieve_response_code( $response );
if ( 201 === $response_code ) { // 201 Transactional email sent
$message_id = wp_remote_retrieve_body( $response );
return $message_id;
} elseif ( 400 <= $response_code ) {
if ( WP_DEBUG ) {
$this->log( $endpoint, $request, $response );
}
}
return false;
}
}

View File

@@ -0,0 +1,191 @@
<?php
/**
* Class for the Stripe API.
*
* @link https://docs.stripe.com/api
*/
class WPCF7_Stripe_API {
const api_version = '2022-11-15';
const partner_id = 'pp_partner_HHbvqLh1AaO7Am';
const app_name = 'WordPress Contact Form 7';
const app_url = 'https://contactform7.com/stripe-integration/';
private $secret;
/**
* Constructor.
*
* @param string $secret Secret key.
*/
public function __construct( $secret ) {
$this->secret = $secret;
}
/**
* Sends a debug information for a remote request to the PHP error log.
*
* @param string $url URL to retrieve.
* @param array $request Request arguments.
* @param array|WP_Error $response The response or WP_Error on failure.
*/
private function log( $url, $request, $response ) {
wpcf7_log_remote_request( $url, $request, $response );
}
/**
* Returns default set of HTTP request headers used for Stripe API.
*
* @link https://docs.stripe.com/building-plugins#setappinfo
*
* @return array An associative array of headers.
*/
private function default_headers() {
$app_info = array(
'name' => self::app_name,
'partner_id' => self::partner_id,
'url' => self::app_url,
'version' => WPCF7_VERSION,
);
$ua = array(
'lang' => 'php',
'lang_version' => PHP_VERSION,
'application' => $app_info,
);
$headers = array(
'Authorization' => sprintf( 'Bearer %s', $this->secret ),
'Stripe-Version' => self::api_version,
'X-Stripe-Client-User-Agent' => wp_json_encode( $ua ),
'User-Agent' => sprintf(
'%1$s/%2$s (%3$s)',
self::app_name,
WPCF7_VERSION,
self::app_url
),
);
return $headers;
}
/**
* Creates a Payment Intent.
*
* @link https://docs.stripe.com/api/payment_intents/create
*
* @param string|array $args Optional. Arguments to control behavior.
* @return array|bool An associative array if 200 OK, false otherwise.
*/
public function create_payment_intent( $args = '' ) {
$args = wp_parse_args( $args, array(
'amount' => 0,
'currency' => '',
'receipt_email' => '',
) );
if ( ! is_email( $args['receipt_email'] ) ) {
unset( $args['receipt_email'] );
}
$endpoint = 'https://api.stripe.com/v1/payment_intents';
$request = array(
'headers' => $this->default_headers(),
'body' => $args,
);
$response = wp_remote_post( sanitize_url( $endpoint ), $request );
if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
if ( WP_DEBUG ) {
$this->log( $endpoint, $request, $response );
}
return false;
}
$response_body = wp_remote_retrieve_body( $response );
$response_body = json_decode( $response_body, true );
return $response_body;
}
/**
* Retrieves a Payment Intent.
*
* @link https://docs.stripe.com/api/payment_intents/retrieve
*
* @param string $id Payment Intent identifier.
* @return array|bool An associative array if 200 OK, false otherwise.
*/
public function retrieve_payment_intent( $id ) {
$endpoint = sprintf(
'https://api.stripe.com/v1/payment_intents/%s',
urlencode( $id )
);
$request = array(
'headers' => $this->default_headers(),
);
$response = wp_remote_get( sanitize_url( $endpoint ), $request );
if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
if ( WP_DEBUG ) {
$this->log( $endpoint, $request, $response );
}
return false;
}
$response_body = wp_remote_retrieve_body( $response );
$response_body = json_decode( $response_body, true );
return $response_body;
}
/**
* Updates a Payment Intent.
*
* @link https://docs.stripe.com/api/payment_intents/update
*
* @param string $id Payment Intent identifier.
* @param array $parameters Parameters.
* @return array|bool An associative array if 200 OK, false otherwise.
*/
public function update_payment_intent( $id, $parameters ) {
$endpoint = sprintf(
'https://api.stripe.com/v1/payment_intents/%s',
urlencode( $id )
);
$request = array(
'headers' => $this->default_headers(),
'body' => wp_parse_args( $parameters, array() ),
);
$response = wp_remote_post( sanitize_url( $endpoint ), $request );
if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
if ( WP_DEBUG ) {
$this->log( $endpoint, $request, $response );
}
return false;
}
$response_body = wp_remote_retrieve_body( $response );
$response_body = json_decode( $response_body, true );
return $response_body;
}
}

View File

@@ -0,0 +1,6 @@
<?php
return array(
'dependencies' => array(),
'version' => WPCF7_VERSION,
);

View File

@@ -0,0 +1 @@
document.addEventListener("DOMContentLoaded",(e=>{const t=()=>{const e=document.querySelectorAll("form.wpcf7-form .wpcf7-stripe");for(let t=0;t<e.length;t++){let r=e[t];r.querySelector("button").disabled=!0;let i=document.createElement("span");i.setAttribute("class","wpcf7-not-valid-tip"),i.insertAdjacentText("beforeend","This form includes a payment widget that requires a modern browser to work."),r.appendChild(i)}};if(void 0===window.wpcf7_stripe)return console.error("window.wpcf7_stripe is not defined."),void t();if("function"!=typeof window.Stripe)return console.error("window.Stripe is not defined."),void t();if("function"!=typeof wpcf7.submit)return console.error("wpcf7.submit is not defined."),void t();const r=Stripe(wpcf7_stripe.publishable_key),i=r.elements();document.addEventListener("wpcf7submit",(e=>{const t=e.detail.unitTag,s=`${t}-ve-stripe-card-element`,n=document.querySelector(`#${t} form`),o=n.closest(".wpcf7").querySelector(".screen-reader-response"),d=n.querySelector(".wpcf7-stripe .wpcf7-form-control-wrap"),c=n.querySelector(".wpcf7-stripe button.first"),a=n.querySelector(".wpcf7-stripe button.second"),l=n.querySelector('[name="_wpcf7_stripe_payment_intent"]');if(!l)return;l.setAttribute("value","");const u=e=>{const t=o.querySelector("ul"),r=t.querySelector(`li#${s}`);r&&r.remove();const i=document.createElement("li");i.setAttribute("id",s),i.insertAdjacentText("beforeend",e.message),t.appendChild(i)},p=e=>{const t=d.querySelector(".wpcf7-form-control");t.classList.add("wpcf7-not-valid"),t.setAttribute("aria-describedby",s);const r=document.createElement("span");r.setAttribute("class","wpcf7-not-valid-tip"),r.setAttribute("aria-hidden","true"),r.insertAdjacentText("beforeend",e.message),d.appendChild(r),d.querySelectorAll("[aria-invalid]").forEach((e=>{e.setAttribute("aria-invalid","true")})),t.closest(".use-floating-validation-tip")&&(t.addEventListener("focus",(e=>{r.setAttribute("style","display: none")})),r.addEventListener("mouseover",(e=>{r.setAttribute("style","display: none")})))},f=()=>{o.querySelectorAll(`ul li#${s}`).forEach((e=>{e.remove()})),d.querySelectorAll(".wpcf7-not-valid-tip").forEach((e=>{e.remove()})),d.querySelectorAll("[aria-invalid]").forEach((e=>{e.setAttribute("aria-invalid","false")})),d.querySelectorAll(".wpcf7-form-control").forEach((e=>{e.removeAttribute("aria-describedby"),e.classList.remove("wpcf7-not-valid")}))};if("payment_required"===e.detail.status){const s=e.detail.apiResponse.stripe.payment_intent;s.id&&l.setAttribute("value",s.id);const o=i.getElement("card")||i.create("card");o.mount(`#${t} .wpcf7-stripe .card-element`),o.clear(),d.classList.remove("hidden"),c.classList.add("hidden"),a.classList.remove("hidden"),a.disabled=!0,o.addEventListener("change",(e=>{if(f(),e.error){const t={message:e.error.message};u(t),p(t),a.disabled=!0}else a.disabled=!1})),a.addEventListener("click",(e=>{f(),a.disabled=!0,n.classList.add("submitting"),wpcf7.blocked||r.confirmCardPayment(s.client_secret,{payment_method:{card:o}}).then((e=>{if(e.error){e.error.decline_code&&["fraudulent","lost_card","merchant_blacklist","pickup_card","restricted_card","security_violation","service_not_allowed","stolen_card","transaction_not_allowed"].includes(e.error.decline_code)&&(wpcf7.blocked=!0),n.classList.remove("submitting");const t={message:e.error.message};u(t),p(t)}else"succeeded"===e.paymentIntent.status&&wpcf7.submit(n)}))}))}else d.classList.add("hidden"),c.classList.remove("hidden"),a.classList.add("hidden"),["mail_sent","mail_failed"].includes(e.detail.status)&&(c.disabled=!0)}))}));

View File

@@ -0,0 +1,300 @@
<?php
if ( ! class_exists( 'WPCF7_Service' ) ) {
return;
}
class WPCF7_Stripe extends WPCF7_Service {
private static $instance;
private $api_keys;
public static function get_instance() {
if ( empty( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
$option = WPCF7::get_option( 'stripe' );
if (
isset( $option['api_keys']['publishable'] ) and
isset( $option['api_keys']['secret'] )
) {
$this->api_keys = array(
'publishable' => $option['api_keys']['publishable'],
'secret' => $option['api_keys']['secret'],
);
}
}
public function get_title() {
return __( 'Stripe', 'contact-form-7' );
}
public function is_active() {
return (bool) $this->get_api_keys();
}
public function api() {
if ( $this->is_active() ) {
$api = new WPCF7_Stripe_API( $this->api_keys['secret'] );
return $api;
}
}
public function get_api_keys() {
return $this->api_keys;
}
public function get_categories() {
return array( 'payments' );
}
public function icon() {
}
public function link() {
echo wp_kses_data( wpcf7_link(
'https://stripe.com/',
'stripe.com'
) );
}
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' => 'stripe' ), $url );
if ( ! empty( $args ) ) {
$url = add_query_arg( $args, $url );
}
return $url;
}
protected function save_data() {
WPCF7::update_option( 'stripe', array(
'api_keys' => $this->api_keys,
) );
}
protected function reset_data() {
$this->api_keys = null;
$this->save_data();
}
public function load( $action = '' ) {
if (
'setup' === $action and
'POST' === wpcf7_superglobal_server( 'REQUEST_METHOD' )
) {
check_admin_referer( 'wpcf7-stripe-setup' );
if ( ! empty( $_POST['reset'] ) ) {
$this->reset_data();
$redirect_to = $this->menu_page_url( 'action=setup' );
} else {
$publishable = wpcf7_superglobal_post( 'publishable' );
$secret = wpcf7_superglobal_post( 'secret' );
if ( $publishable and $secret ) {
$this->api_keys = array(
'publishable' => $publishable,
'secret' => $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',
) );
}
}
wp_safe_redirect( $redirect_to );
exit();
}
}
public function admin_notice( $message = '' ) {
if ( 'invalid' === $message ) {
wp_admin_notice(
__( '<strong>Error:</strong> Invalid key values.', 'contact-form-7' ),
array( 'type' => 'error' )
);
}
if ( 'success' === $message ) {
wp_admin_notice(
__( 'Settings saved.', 'contact-form-7' ),
array( 'type' => 'success' )
);
}
}
public function display( $action = '' ) {
$formatter = new WPCF7_HTMLFormatter( array(
'allowed_html' => array_merge( wpcf7_kses_allowed_html(), array(
'form' => array(
'action' => true,
'method' => true,
),
) ),
) );
$formatter->append_start_tag( 'p' );
$formatter->append_preformatted(
esc_html( __( 'Stripe is a simple and powerful way to accept payments online. Stripe has no setup fees, no monthly fees, and no hidden costs. Millions of businesses rely on Stripe&#8217;s software tools to accept payments securely and expand globally.', 'contact-form-7' ) )
);
$formatter->end_tag( 'p' );
$formatter->append_start_tag( 'p' );
$formatter->append_start_tag( 'strong' );
$formatter->append_preformatted(
wpcf7_link(
__( 'https://contactform7.com/stripe-integration/', 'contact-form-7' ),
__( 'Stripe integration', 'contact-form-7' )
)
);
$formatter->end_tag( 'p' );
if ( $this->is_active() ) {
$formatter->append_start_tag( 'p', array(
'class' => 'dashicons-before dashicons-yes',
) );
$formatter->append_preformatted(
esc_html( __( 'Stripe is active on this site.', 'contact-form-7' ) )
);
$formatter->end_tag( 'p' );
}
if ( 'setup' === $action ) {
$formatter->call_user_func( function () {
$this->display_setup();
} );
} elseif ( is_ssl() or WP_DEBUG ) {
$formatter->append_start_tag( 'p' );
$formatter->append_start_tag( 'a', array(
'href' => esc_url( $this->menu_page_url( 'action=setup' ) ),
'class' => 'button',
) );
$formatter->append_preformatted(
esc_html( __( 'Setup integration', 'contact-form-7' ) )
);
$formatter->end_tag( 'p' );
} else {
$formatter->append_start_tag( 'p', array(
'class' => 'dashicons-before dashicons-warning',
) );
$formatter->append_preformatted(
esc_html( __( 'Stripe is not available on this site. It requires an HTTPS-enabled site.', 'contact-form-7' ) )
);
$formatter->end_tag( 'p' );
}
$formatter->print();
}
private function display_setup() {
$api_keys = $this->get_api_keys();
if ( $api_keys ) {
$publishable = $api_keys['publishable'];
$secret = $api_keys['secret'];
} else {
$publishable = '';
$secret = '';
}
?>
<form method="post" action="<?php echo esc_url( $this->menu_page_url( 'action=setup' ) ); ?>">
<?php wp_nonce_field( 'wpcf7-stripe-setup' ); ?>
<table class="form-table">
<tbody>
<tr>
<th scope="row"><label for="publishable"><?php echo esc_html( __( 'Publishable Key', 'contact-form-7' ) ); ?></label></th>
<td><?php
if ( $this->is_active() ) {
echo esc_html( $publishable );
echo sprintf(
'<input type="hidden" value="%s" id="publishable" name="publishable" />',
esc_attr( $publishable )
);
} else {
echo sprintf(
'<input type="text" aria-required="true" value="%s" id="publishable" name="publishable" class="regular-text code" />',
esc_attr( $publishable )
);
}
?></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 ) );
echo sprintf(
'<input type="hidden" value="%s" id="secret" name="secret" />',
esc_attr( $secret )
);
} else {
echo sprintf(
'<input type="text" aria-required="true" value="%s" id="secret" name="secret" class="regular-text code" />',
esc_attr( $secret )
);
}
?></td>
</tr>
</tbody>
</table>
<?php
if ( $this->is_active() ) {
submit_button(
_x( 'Remove Keys', 'API keys', 'contact-form-7' ),
'small', 'reset'
);
} else {
submit_button( __( 'Save Changes', 'contact-form-7' ) );
}
?>
</form>
<?php
}
}

View File

@@ -0,0 +1,406 @@
<?php
/**
* Stripe module main file
*
* @link https://contactform7.com/stripe-integration/
*/
wpcf7_include_module_file( 'stripe/service.php' );
wpcf7_include_module_file( 'stripe/api.php' );
add_action(
'wpcf7_init',
'wpcf7_stripe_register_service',
50, 0
);
/**
* Registers the Stripe service.
*/
function wpcf7_stripe_register_service() {
$integration = WPCF7_Integration::get_instance();
$integration->add_service( 'stripe',
WPCF7_Stripe::get_instance()
);
}
add_action(
'wpcf7_enqueue_scripts',
'wpcf7_stripe_enqueue_scripts',
10, 0
);
/**
* Enqueues scripts and styles for the Stripe module.
*/
function wpcf7_stripe_enqueue_scripts() {
$service = WPCF7_Stripe::get_instance();
if ( ! $service->is_active() ) {
return;
}
wp_enqueue_style( 'wpcf7-stripe',
wpcf7_plugin_url( 'modules/stripe/style.css' ),
array(), WPCF7_VERSION, 'all'
);
wp_register_script(
'stripe',
'https://js.stripe.com/v3/',
array(),
null,
array( 'in_footer' => true )
);
$assets = include wpcf7_plugin_path( 'modules/stripe/index.asset.php' );
$assets = wp_parse_args( $assets, array(
'dependencies' => array(),
'version' => WPCF7_VERSION,
) );
wp_enqueue_script(
'wpcf7-stripe',
wpcf7_plugin_url( 'modules/stripe/index.js' ),
array_merge(
$assets['dependencies'],
array(
'wp-polyfill',
'contact-form-7',
'stripe',
)
),
$assets['version'],
array( 'in_footer' => true )
);
$api_keys = $service->get_api_keys();
if ( $api_keys['publishable'] ) {
wp_add_inline_script( 'wpcf7-stripe',
sprintf(
'var wpcf7_stripe = %s;',
wp_json_encode( array(
'publishable_key' => $api_keys['publishable'],
), JSON_PRETTY_PRINT )
),
'before'
);
}
}
add_filter(
'wpcf7_skip_spam_check',
'wpcf7_stripe_skip_spam_check',
10, 2
);
/**
* Skips the spam check if it is not necessary.
*
* @return bool True if the spam check is not necessary.
*/
function wpcf7_stripe_skip_spam_check( $skip_spam_check, $submission ) {
$service = WPCF7_Stripe::get_instance();
if ( ! $service->is_active() ) {
return $skip_spam_check;
}
$pi_id = (string) wpcf7_superglobal_post( '_wpcf7_stripe_payment_intent' );
if ( $pi_id ) {
$payment_intent = $service->api()->retrieve_payment_intent( $pi_id );
if (
isset( $payment_intent['metadata']['wpcf7_submission_timestamp'] )
) {
// This PI has already been used. Ignore.
return $skip_spam_check;
}
if (
isset( $payment_intent['status'] ) and
'succeeded' === $payment_intent['status']
) {
$submission->push( 'payment_intent', $pi_id );
$service->api()->update_payment_intent( $pi_id, array(
'metadata' => array_merge( $payment_intent['metadata'], array(
'wpcf7_submission_timestamp' => $submission->get_meta( 'timestamp' ),
) ),
) );
}
}
if (
! empty( $submission->pull( 'payment_intent' ) ) and
$submission->verify_posted_data_hash()
) {
$skip_spam_check = true;
}
return $skip_spam_check;
}
add_filter(
'wpcf7_spam',
'wpcf7_stripe_verify_payment_intent',
6, 2
);
/**
* Verifies submitted Stripe Payment Intent ID.
*/
function wpcf7_stripe_verify_payment_intent( $spam, $submission ) {
$service = WPCF7_Stripe::get_instance();
if ( ! $service->is_active() ) {
return $spam;
}
$pi_id = (string) wpcf7_superglobal_post( '_wpcf7_stripe_payment_intent' );
if ( $pi_id ) {
$payment_intent = $service->api()->retrieve_payment_intent( $pi_id );
if (
! $payment_intent or
isset( $payment_intent['metadata']['wpcf7_submission_timestamp'] )
) {
$spam = true;
$submission->add_spam_log( array(
'agent' => 'stripe',
'reason' => __(
'Invalid Stripe Payment Intent ID detected.',
'contact-form-7'
),
) );
}
}
return $spam;
}
add_action(
'wpcf7_before_send_mail',
'wpcf7_stripe_before_send_mail',
10, 3
);
/**
* Creates Stripe's Payment Intent.
*/
function wpcf7_stripe_before_send_mail( $contact_form, &$abort, $submission ) {
$service = WPCF7_Stripe::get_instance();
if ( ! $service->is_active() ) {
return;
}
$tags = $contact_form->scan_form_tags( array( 'type' => 'stripe' ) );
if ( ! $tags ) {
return;
}
if ( ! empty( $submission->pull( 'payment_intent' ) ) ) {
return;
}
$tag = $tags[0];
$amount = $tag->get_option( 'amount', 'int', true );
$currency = $tag->get_option( 'currency', '[a-zA-Z]{3}', true );
$payment_intent_params = apply_filters(
'wpcf7_stripe_payment_intent_parameters',
array(
'amount' => $amount ? absint( $amount ) : null,
'currency' => $currency ? strtolower( $currency ) : null,
'receipt_email' => $submission->get_posted_data( 'your-email' ),
)
);
$payment_intent = $service->api()->create_payment_intent(
$payment_intent_params
);
if ( $payment_intent ) {
$submission->add_result_props( array(
'stripe' => array(
'payment_intent' => array(
'id' => $payment_intent['id'],
'client_secret' => $payment_intent['client_secret'],
),
),
) );
$submission->set_status( 'payment_required' );
$submission->set_response(
__( 'Payment is required. Please pay by credit card.', 'contact-form-7' )
);
}
$abort = true;
}
/**
* Returns payment link URL.
*
* @param string $pi_id Payment Intent ID.
* @return string The URL.
*/
function wpcf7_stripe_get_payment_link( $pi_id ) {
return sprintf(
'https://dashboard.stripe.com/payments/%s',
urlencode( $pi_id )
);
}
add_filter(
'wpcf7_special_mail_tags',
'wpcf7_stripe_smt',
10, 4
);
/**
* Registers the [_stripe_payment_link] special mail-tag.
*/
function wpcf7_stripe_smt( $output, $tag_name, $html, $mail_tag = null ) {
if ( '_stripe_payment_link' === $tag_name ) {
$submission = WPCF7_Submission::get_instance();
$pi_id = $submission->pull( 'payment_intent' );
if ( ! empty( $pi_id ) ) {
$output = wpcf7_stripe_get_payment_link( $pi_id );
}
}
return $output;
}
add_filter(
'wpcf7_flamingo_inbound_message_parameters',
'wpcf7_stripe_add_flamingo_inbound_message_params',
10, 1
);
/**
* Adds Stripe-related meta data to Flamingo Inbound Message parameters.
*/
function wpcf7_stripe_add_flamingo_inbound_message_params( $args ) {
$submission = WPCF7_Submission::get_instance();
$pi_id = $submission->pull( 'payment_intent' );
if ( empty( $pi_id ) ) {
return $args;
}
$pi_link = wpcf7_stripe_get_payment_link( $pi_id );
$meta = (array) $args['meta'];
$meta['stripe_payment_link'] = $pi_link;
$args['meta'] = $meta;
return $args;
}
add_action(
'wpcf7_init',
'wpcf7_add_form_tag_stripe',
10, 0
);
/**
* Registers the stripe form-tag handler.
*/
function wpcf7_add_form_tag_stripe() {
wpcf7_add_form_tag(
'stripe',
'wpcf7_stripe_form_tag_handler',
array(
'display-block' => true,
'singular' => true,
)
);
}
/**
* Defines the stripe form-tag handler.
*
* @return string HTML content that replaces a stripe form-tag.
*/
function wpcf7_stripe_form_tag_handler( $tag ) {
$card_element = sprintf(
'<div %s></div>',
wpcf7_format_atts( array(
'class' => 'card-element wpcf7-form-control',
'aria-invalid' => 'false',
) )
);
$card_element = sprintf(
'<div class="wpcf7-form-control-wrap hidden">%s</div>',
$card_element
);
$button_1_label = __( 'Proceed to checkout', 'contact-form-7' );
if ( isset( $tag->values[0] ) ) {
$button_1_label = trim( $tag->values[0] );
}
$button_1 = sprintf(
'<button %1$s>%2$s</button>',
wpcf7_format_atts( array(
'type' => 'submit',
'class' => 'first',
) ),
esc_html( $button_1_label )
);
$button_2_label = __( 'Complete payment', 'contact-form-7' );
if ( isset( $tag->values[1] ) ) {
$button_2_label = trim( $tag->values[1] );
}
$button_2 = sprintf(
'<button %1$s>%2$s</button>',
wpcf7_format_atts( array(
'type' => 'button',
'class' => 'second hidden',
) ),
esc_html( $button_2_label )
);
$buttons = sprintf(
'<span class="buttons has-spinner">%1$s %2$s</span>',
$button_1, $button_2
);
return sprintf(
'<div class="wpcf7-stripe">%1$s %2$s %3$s</div>',
$card_element,
$buttons,
'<input type="hidden" name="_wpcf7_stripe_payment_intent" value="" />'
);
}

View File

@@ -0,0 +1,18 @@
.wpcf7 .wpcf7-stripe .wpcf7-form-control-wrap {
margin: .6em 0;
}
.wpcf7 .wpcf7-stripe .wpcf7-form-control {
display: block;
background: #f6f7f7;
padding: 12px 12px;
border: 1px solid #787c82;
}
.wpcf7 .wpcf7-stripe button:disabled {
cursor: not-allowed;
}
.wpcf7 .wpcf7-stripe .hidden {
display: none;
}

View File

@@ -0,0 +1,115 @@
<?php
/**
** A base module for [submit]
**/
/* form_tag handler */
add_action( 'wpcf7_init', 'wpcf7_add_form_tag_submit', 10, 0 );
function wpcf7_add_form_tag_submit() {
wpcf7_add_form_tag( 'submit', 'wpcf7_submit_form_tag_handler' );
}
function wpcf7_submit_form_tag_handler( $tag ) {
$class = wpcf7_form_controls_class( $tag->type, 'has-spinner' );
$atts = array();
$atts['class'] = $tag->get_class_option( $class );
$atts['id'] = $tag->get_id_option();
$atts['tabindex'] = $tag->get_option( 'tabindex', 'signed_int', true );
$value = isset( $tag->values[0] ) ? $tag->values[0] : '';
if ( empty( $value ) ) {
$value = __( 'Send', 'contact-form-7' );
}
$atts['type'] = 'submit';
$atts['value'] = $value;
$atts = wpcf7_format_atts( $atts );
$html = sprintf( '<input %1$s />', $atts );
return $html;
}
/* Tag generator */
add_action( 'wpcf7_admin_init', 'wpcf7_add_tag_generator_submit', 55, 0 );
function wpcf7_add_tag_generator_submit() {
$tag_generator = WPCF7_TagGenerator::get_instance();
$tag_generator->add( 'submit', __( 'submit', 'contact-form-7' ),
'wpcf7_tag_generator_submit',
array( 'version' => '2' )
);
}
function wpcf7_tag_generator_submit( $contact_form, $options ) {
$field_types = array(
'submit' => array(
'display_name' => __( 'Submit button', 'contact-form-7' ),
'heading' => __( 'Submit button form-tag generator', 'contact-form-7' ),
'description' => __( 'Generates a form-tag for a <a href="https://contactform7.com/submit-button/">submit button</a>.', 'contact-form-7' ),
),
);
$tgg = new WPCF7_TagGeneratorGenerator( $options['content'] );
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'header', array(
'class' => 'description-box',
) );
$formatter->append_start_tag( 'h3' );
$formatter->append_preformatted(
esc_html( $field_types['submit']['heading'] )
);
$formatter->end_tag( 'h3' );
$formatter->append_start_tag( 'p' );
$formatter->append_preformatted(
wp_kses_data( $field_types['submit']['description'] )
);
$formatter->end_tag( 'header' );
$formatter->append_start_tag( 'div', array(
'class' => 'control-box',
) );
$formatter->call_user_func( static function () use ( $tgg, $field_types ) {
$tgg->print( 'field_type', array(
'select_options' => array(
'submit' => $field_types['submit']['display_name'],
),
) );
$tgg->print( 'class_attr' );
$tgg->print( 'default_value', array(
'title' => __( 'Label', 'contact-form-7' ),
) );
} );
$formatter->end_tag( 'div' );
$formatter->append_start_tag( 'footer', array(
'class' => 'insert-box',
) );
$formatter->call_user_func( static function () use ( $tgg, $field_types ) {
$tgg->print( 'insert_box_content' );
} );
$formatter->print();
}

View File

@@ -0,0 +1,325 @@
<?php
/**
** A base module for the following types of tags:
** [text] and [text*] # Single-line text
** [email] and [email*] # Email address
** [url] and [url*] # URL
** [tel] and [tel*] # Telephone number
**/
/* form_tag handler */
add_action( 'wpcf7_init', 'wpcf7_add_form_tag_text', 10, 0 );
function wpcf7_add_form_tag_text() {
wpcf7_add_form_tag(
array( 'text', 'text*', 'email', 'email*', 'url', 'url*', 'tel', 'tel*' ),
'wpcf7_text_form_tag_handler',
array(
'name-attr' => true,
)
);
}
function wpcf7_text_form_tag_handler( $tag ) {
if ( empty( $tag->name ) ) {
return '';
}
$validation_error = wpcf7_get_validation_error( $tag->name );
$class = wpcf7_form_controls_class( $tag->type, 'wpcf7-text' );
if ( in_array( $tag->basetype, array( 'email', 'url', 'tel' ), true ) ) {
$class .= ' wpcf7-validates-as-' . $tag->basetype;
}
if ( $validation_error ) {
$class .= ' wpcf7-not-valid';
}
$atts = array();
$atts['size'] = $tag->get_size_option( '40' );
$atts['maxlength'] = $tag->get_maxlength_option( '400' );
$atts['minlength'] = $tag->get_minlength_option();
if (
$atts['maxlength'] and $atts['minlength'] and
$atts['maxlength'] < $atts['minlength']
) {
unset( $atts['maxlength'], $atts['minlength'] );
}
$atts['class'] = $tag->get_class_option( $class );
$atts['id'] = $tag->get_id_option();
$atts['list'] = $tag->get_option( 'list', 'id', true );
$atts['tabindex'] = $tag->get_option( 'tabindex', 'signed_int', true );
$atts['readonly'] = $tag->has_option( 'readonly' );
$atts['autocomplete'] = $tag->get_autocomplete_option();
if ( $tag->is_required() ) {
$atts['aria-required'] = 'true';
}
if ( $validation_error ) {
$atts['aria-invalid'] = 'true';
$atts['aria-describedby'] = wpcf7_get_validation_error_reference(
$tag->name
);
} else {
$atts['aria-invalid'] = 'false';
}
$value = (string) reset( $tag->values );
if ( $tag->has_option( 'placeholder' ) or $tag->has_option( 'watermark' ) ) {
$atts['placeholder'] = $value;
$value = '';
}
$value = $tag->get_default_option( $value );
$value = wpcf7_get_hangover( $tag->name, $value );
$atts['value'] = $value;
$atts['type'] = $tag->basetype;
$atts['name'] = $tag->name;
$html = sprintf(
'<span class="wpcf7-form-control-wrap" data-name="%1$s"><input %2$s />%3$s</span>',
esc_attr( $tag->name ),
wpcf7_format_atts( $atts ),
$validation_error
);
return $html;
}
add_action(
'wpcf7_swv_create_schema',
'wpcf7_swv_add_text_rules',
10, 2
);
function wpcf7_swv_add_text_rules( $schema, $contact_form ) {
$tags = $contact_form->scan_form_tags( array(
'basetype' => array( 'text', 'email', 'url', 'tel' ),
) );
foreach ( $tags as $tag ) {
if ( $tag->is_required() ) {
$schema->add_rule(
wpcf7_swv_create_rule( 'required', array(
'field' => $tag->name,
'error' => wpcf7_get_message( 'invalid_required' ),
) )
);
}
if ( 'email' === $tag->basetype ) {
$schema->add_rule(
wpcf7_swv_create_rule( 'email', array(
'field' => $tag->name,
'error' => wpcf7_get_message( 'invalid_email' ),
) )
);
}
if ( 'url' === $tag->basetype ) {
$schema->add_rule(
wpcf7_swv_create_rule( 'url', array(
'field' => $tag->name,
'error' => wpcf7_get_message( 'invalid_url' ),
) )
);
}
if ( 'tel' === $tag->basetype ) {
$schema->add_rule(
wpcf7_swv_create_rule( 'tel', array(
'field' => $tag->name,
'error' => wpcf7_get_message( 'invalid_tel' ),
) )
);
}
if ( $minlength = $tag->get_minlength_option() ) {
$schema->add_rule(
wpcf7_swv_create_rule( 'minlength', array(
'field' => $tag->name,
'threshold' => absint( $minlength ),
'error' => wpcf7_get_message( 'invalid_too_short' ),
) )
);
}
if ( $maxlength = $tag->get_maxlength_option( '400' ) ) {
$schema->add_rule(
wpcf7_swv_create_rule( 'maxlength', array(
'field' => $tag->name,
'threshold' => absint( $maxlength ),
'error' => wpcf7_get_message( 'invalid_too_long' ),
) )
);
}
}
}
/* Messages */
add_filter( 'wpcf7_messages', 'wpcf7_text_messages', 10, 1 );
function wpcf7_text_messages( $messages ) {
$messages = array_merge( $messages, array(
'invalid_email' => array(
'description' =>
__( 'Email address that the sender entered is invalid', 'contact-form-7' ),
'default' =>
__( 'Please enter an email address.', 'contact-form-7' ),
),
'invalid_url' => array(
'description' =>
__( 'URL that the sender entered is invalid', 'contact-form-7' ),
'default' =>
__( 'Please enter a URL.', 'contact-form-7' ),
),
'invalid_tel' => array(
'description' =>
__( 'Telephone number that the sender entered is invalid', 'contact-form-7' ),
'default' =>
__( 'Please enter a telephone number.', 'contact-form-7' ),
),
) );
return $messages;
}
/* Tag generator */
add_action( 'wpcf7_admin_init', 'wpcf7_add_tag_generator_text', 15, 0 );
function wpcf7_add_tag_generator_text() {
$tag_generator = WPCF7_TagGenerator::get_instance();
$basetypes = array(
'text' => __( 'text', 'contact-form-7' ),
'email' => __( 'email', 'contact-form-7' ),
'url' => __( 'URL', 'contact-form-7' ),
'tel' => __( 'tel', 'contact-form-7' ),
);
foreach ( $basetypes as $id => $title ) {
$tag_generator->add( $id, $title,
'wpcf7_tag_generator_text',
array( 'version' => '2' )
);
}
}
function wpcf7_tag_generator_text( $contact_form, $options ) {
$field_types = array(
'text' => array(
'display_name' => __( 'Text field', 'contact-form-7' ),
'heading' => __( 'Text field form-tag generator', 'contact-form-7' ),
'description' => __( 'Generates a form-tag for a <a href="https://contactform7.com/text-fields/">single-line plain text input field</a>.', 'contact-form-7' ),
'maybe_purpose' => 'author_name',
),
'email' => array(
'display_name' => __( 'Email address field', 'contact-form-7' ),
'heading' => __( 'Email address field form-tag generator', 'contact-form-7' ),
'description' => __( 'Generates a form-tag for an <a href="https://contactform7.com/text-fields/">email address input field</a>.', 'contact-form-7' ),
'maybe_purpose' => 'author_email',
),
'url' => array(
'display_name' => __( 'URL field', 'contact-form-7' ),
'heading' => __( 'URL field form-tag generator', 'contact-form-7' ),
'description' => __( 'Generates a form-tag for a <a href="https://contactform7.com/text-fields/">URL input field</a>.', 'contact-form-7' ),
'maybe_purpose' => 'author_url',
),
'tel' => array(
'display_name' => __( 'Telephone number field', 'contact-form-7' ),
'heading' => __( 'Telephone number field form-tag generator', 'contact-form-7' ),
'description' => __( 'Generates a form-tag for a <a href="https://contactform7.com/text-fields/">telephone number input field</a>.', 'contact-form-7' ),
'maybe_purpose' => 'author_tel',
),
);
$basetype = $options['id'];
if ( ! in_array( $basetype, array_keys( $field_types ), true ) ) {
$basetype = 'text';
}
$tgg = new WPCF7_TagGeneratorGenerator( $options['content'] );
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'header', array(
'class' => 'description-box',
) );
$formatter->append_start_tag( 'h3' );
$formatter->append_preformatted(
esc_html( $field_types[$basetype]['heading'] )
);
$formatter->end_tag( 'h3' );
$formatter->append_start_tag( 'p' );
$formatter->append_preformatted(
wp_kses_data( $field_types[$basetype]['description'] )
);
$formatter->end_tag( 'header' );
$formatter->append_start_tag( 'div', array(
'class' => 'control-box',
) );
$formatter->call_user_func( static function () use ( $tgg, $field_types, $basetype ) {
$tgg->print( 'field_type', array(
'with_required' => true,
'select_options' => array(
$basetype => $field_types[$basetype]['display_name'],
),
) );
$tgg->print( 'field_name', array(
'ask_if' => $field_types[$basetype]['maybe_purpose']
) );
$tgg->print( 'class_attr' );
$tgg->print( 'min_max', array(
'title' => __( 'Length', 'contact-form-7' ),
'min_option' => 'minlength:',
'max_option' => 'maxlength:',
) );
$tgg->print( 'default_value', array(
'with_placeholder' => true,
) );
} );
$formatter->end_tag( 'div' );
$formatter->append_start_tag( 'footer', array(
'class' => 'insert-box',
) );
$formatter->call_user_func( static function () use ( $tgg, $field_types ) {
$tgg->print( 'insert_box_content' );
$tgg->print( 'mail_tag_tip' );
} );
$formatter->print();
}

View File

@@ -0,0 +1,221 @@
<?php
/**
** A base module for [textarea] and [textarea*]
**/
/* form_tag handler */
add_action( 'wpcf7_init', 'wpcf7_add_form_tag_textarea', 10, 0 );
function wpcf7_add_form_tag_textarea() {
wpcf7_add_form_tag( array( 'textarea', 'textarea*' ),
'wpcf7_textarea_form_tag_handler', array( 'name-attr' => true )
);
}
function wpcf7_textarea_form_tag_handler( $tag ) {
if ( empty( $tag->name ) ) {
return '';
}
$validation_error = wpcf7_get_validation_error( $tag->name );
$class = wpcf7_form_controls_class( $tag->type );
if ( $validation_error ) {
$class .= ' wpcf7-not-valid';
}
$atts = array();
$atts['cols'] = $tag->get_cols_option( '40' );
$atts['rows'] = $tag->get_rows_option( '10' );
$atts['maxlength'] = $tag->get_maxlength_option( '2000' );
$atts['minlength'] = $tag->get_minlength_option();
if (
$atts['maxlength'] and $atts['minlength'] and
$atts['maxlength'] < $atts['minlength']
) {
unset( $atts['maxlength'], $atts['minlength'] );
}
$atts['class'] = $tag->get_class_option( $class );
$atts['id'] = $tag->get_id_option();
$atts['tabindex'] = $tag->get_option( 'tabindex', 'signed_int', true );
$atts['readonly'] = $tag->has_option( 'readonly' );
$atts['autocomplete'] = $tag->get_autocomplete_option();
if ( $tag->is_required() ) {
$atts['aria-required'] = 'true';
}
if ( $validation_error ) {
$atts['aria-invalid'] = 'true';
$atts['aria-describedby'] = wpcf7_get_validation_error_reference(
$tag->name
);
} else {
$atts['aria-invalid'] = 'false';
}
$value = empty( $tag->content )
? (string) reset( $tag->values )
: $tag->content;
if ( $tag->has_option( 'placeholder' ) or $tag->has_option( 'watermark' ) ) {
$atts['placeholder'] = $value;
$value = '';
}
$value = $tag->get_default_option( $value );
$value = wpcf7_get_hangover( $tag->name, $value );
$atts['name'] = $tag->name;
$html = sprintf(
'<span class="wpcf7-form-control-wrap" data-name="%1$s"><textarea %2$s>%3$s</textarea>%4$s</span>',
esc_attr( $tag->name ),
wpcf7_format_atts( $atts ),
esc_textarea( $value ),
$validation_error
);
return $html;
}
add_action(
'wpcf7_swv_create_schema',
'wpcf7_swv_add_textarea_rules',
10, 2
);
function wpcf7_swv_add_textarea_rules( $schema, $contact_form ) {
$tags = $contact_form->scan_form_tags( array(
'basetype' => array( 'textarea' ),
) );
foreach ( $tags as $tag ) {
if ( $tag->is_required() ) {
$schema->add_rule(
wpcf7_swv_create_rule( 'required', array(
'field' => $tag->name,
'error' => wpcf7_get_message( 'invalid_required' ),
) )
);
}
if ( $minlength = $tag->get_minlength_option() ) {
$schema->add_rule(
wpcf7_swv_create_rule( 'minlength', array(
'field' => $tag->name,
'threshold' => absint( $minlength ),
'error' => wpcf7_get_message( 'invalid_too_short' ),
) )
);
}
if ( $maxlength = $tag->get_maxlength_option( '2000' ) ) {
$schema->add_rule(
wpcf7_swv_create_rule( 'maxlength', array(
'field' => $tag->name,
'threshold' => absint( $maxlength ),
'error' => wpcf7_get_message( 'invalid_too_long' ),
) )
);
}
}
}
/* Tag generator */
add_action( 'wpcf7_admin_init', 'wpcf7_add_tag_generator_textarea', 20, 0 );
function wpcf7_add_tag_generator_textarea() {
$tag_generator = WPCF7_TagGenerator::get_instance();
$tag_generator->add( 'textarea',
__( 'text area', 'contact-form-7' ),
'wpcf7_tag_generator_textarea',
array( 'version' => '2' )
);
}
function wpcf7_tag_generator_textarea( $contact_form, $options ) {
$field_types = array(
'textarea' => array(
'display_name' => __( 'Text area', 'contact-form-7' ),
'heading' => __( 'Text area form-tag generator', 'contact-form-7' ),
'description' => __( 'Generates a form-tag for a <a href="https://contactform7.com/text-fields/">multi-line plain text input area</a>.', 'contact-form-7' ),
),
);
$tgg = new WPCF7_TagGeneratorGenerator( $options['content'] );
$formatter = new WPCF7_HTMLFormatter();
$formatter->append_start_tag( 'header', array(
'class' => 'description-box',
) );
$formatter->append_start_tag( 'h3' );
$formatter->append_preformatted(
esc_html( $field_types['textarea']['heading'] )
);
$formatter->end_tag( 'h3' );
$formatter->append_start_tag( 'p' );
$formatter->append_preformatted(
wp_kses_data( $field_types['textarea']['description'] )
);
$formatter->end_tag( 'header' );
$formatter->append_start_tag( 'div', array(
'class' => 'control-box',
) );
$formatter->call_user_func( static function () use ( $tgg, $field_types ) {
$tgg->print( 'field_type', array(
'with_required' => true,
'select_options' => array(
'textarea' => $field_types['textarea']['display_name'],
),
) );
$tgg->print( 'field_name' );
$tgg->print( 'class_attr' );
$tgg->print( 'min_max', array(
'title' => __( 'Length', 'contact-form-7' ),
'min_option' => 'minlength:',
'max_option' => 'maxlength:',
) );
$tgg->print( 'default_value', array(
'with_placeholder' => true,
'use_content' => true,
) );
} );
$formatter->end_tag( 'div' );
$formatter->append_start_tag( 'footer', array(
'class' => 'insert-box',
) );
$formatter->call_user_func( static function () use ( $tgg, $field_types ) {
$tgg->print( 'insert_box_content' );
$tgg->print( 'mail_tag_tip' );
} );
$formatter->print();
}

View File

@@ -0,0 +1,382 @@
<?php
/**
* Turnstile service main file
*/
if ( ! class_exists( 'WPCF7_Service' ) ) {
return;
}
class WPCF7_Turnstile extends WPCF7_Service {
private static $instance;
private $sitekeys;
/**
* Returns the singleton instance of the class.
*/
public static function get_instance() {
if ( empty( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* The constructor.
*/
private function __construct() {
$this->sitekeys = WPCF7::get_option( 'turnstile' );
}
/**
* Returns the service title.
*/
public function get_title() {
return __( 'Turnstile', 'contact-form-7' );
}
/**
* Returns true if the service is active.
*/
public function is_active() {
$sitekey = $this->get_sitekey();
$secret = $this->get_secret( $sitekey );
return $sitekey && $secret;
}
/**
* Returns an array of categories to which the service belongs to.
*/
public function get_categories() {
return array( 'spam_protection' );
}
/**
* Returns the icon that represents the service.
*/
public function icon() {
}
/**
* Returns a link to the service provider.
*/
public function link() {
echo wp_kses_data( wpcf7_link(
'https://www.cloudflare.com/application-services/products/turnstile/',
'cloudflare.com'
) );
}
/**
* Returns a sitekey.
*/
public function get_sitekey() {
$sitekeys = (array) $this->sitekeys;
$sitekey = array_key_first( $sitekeys ) ?? '';
return apply_filters( 'wpcf7_turnstile_sitekey', $sitekey );
}
/**
* Returns the secret key that is paired with the given sitekey.
*/
public function get_secret( $sitekey ) {
$sitekeys = (array) $this->sitekeys;
$secret = $sitekeys[$sitekey] ?? '';
return apply_filters( 'wpcf7_turnstile_secret', $secret );
}
/**
* Logs an API response.
*/
protected function log( $url, $request, $response ) {
wpcf7_log_remote_request( $url, $request, $response );
}
/**
* Verifies a response token.
*/
public function verify( $token ) {
$is_human = false;
if ( empty( $token ) or ! $this->is_active() ) {
return $is_human;
}
$endpoint = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
$sitekey = $this->get_sitekey();
$secret = $this->get_secret( $sitekey );
$request = array(
'body' => array(
'secret' => $secret,
'response' => $token,
),
);
$response = wp_remote_post( sanitize_url( $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 );
if ( $response_body['success'] ) {
$is_human = true;
}
if ( $submission = WPCF7_Submission::get_instance() ) {
$submission->push( 'turnstile', array(
'response' => $response_body,
) );
}
return $is_human;
}
/**
* Returns the menu page URL for the service configuration.
*/
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' => 'turnstile' ), $url );
if ( ! empty( $args ) ) {
$url = add_query_arg( $args, $url );
}
return $url;
}
/**
* Saves the service configuration data.
*/
protected function save_data() {
WPCF7::update_option( 'turnstile', $this->sitekeys );
}
/**
* Resets the service configuration data.
*/
protected function reset_data() {
$this->sitekeys = null;
$this->save_data();
}
/**
* The loading process of the service configuration page.
*/
public function load( $action = '' ) {
if (
'setup' === $action and
'POST' === wpcf7_superglobal_server( 'REQUEST_METHOD' )
) {
check_admin_referer( 'wpcf7-turnstile-setup' );
if ( wpcf7_superglobal_post( 'reset' ) ) {
$this->reset_data();
$redirect_to = $this->menu_page_url( 'action=setup' );
} else {
$sitekey = wpcf7_superglobal_post( 'sitekey' );
$secret = wpcf7_superglobal_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',
) );
}
}
wp_safe_redirect( $redirect_to );
exit();
}
}
/**
* Displays a notice on the integration page.
*/
public function admin_notice( $message = '' ) {
if ( 'invalid' === $message ) {
wp_admin_notice(
__( '<strong>Error:</strong> Invalid key values.', 'contact-form-7' ),
array( 'type' => 'error' )
);
}
if ( 'success' === $message ) {
wp_admin_notice(
__( 'Settings saved.', 'contact-form-7' ),
array( 'type' => 'success' )
);
}
}
/**
* Displays the service configuration box.
*/
public function display( $action = '' ) {
$formatter = new WPCF7_HTMLFormatter( array(
'allowed_html' => array_merge( wpcf7_kses_allowed_html(), array(
'form' => array(
'action' => true,
'method' => true,
),
) ),
) );
$formatter->append_start_tag( 'p' );
$formatter->append_preformatted(
esc_html( __( 'Turnstile is Cloudflare&#8217;s smart CAPTCHA alternative, which confirms web visitors are real and blocks unwanted bots without slowing down web experiences for real users.', 'contact-form-7' ) )
);
$formatter->end_tag( 'p' );
$formatter->append_start_tag( 'p' );
$formatter->append_start_tag( 'strong' );
$formatter->append_preformatted(
wpcf7_link(
__( 'https://contactform7.com/turnstile-integration/', 'contact-form-7' ),
__( 'Cloudflare Turnstile integration', 'contact-form-7' )
)
);
$formatter->end_tag( 'p' );
if ( $this->is_active() ) {
$formatter->append_start_tag( 'p', array(
'class' => 'dashicons-before dashicons-yes',
) );
$formatter->append_preformatted(
esc_html( __( 'Turnstile is active on this site.', 'contact-form-7' ) )
);
$formatter->end_tag( 'p' );
}
if ( 'setup' === $action ) {
$formatter->call_user_func( function () {
$this->display_setup();
} );
} else {
$formatter->append_start_tag( 'p' );
$formatter->append_start_tag( 'a', array(
'href' => esc_url( $this->menu_page_url( 'action=setup' ) ),
'class' => 'button',
) );
$formatter->append_preformatted(
esc_html( __( 'Setup integration', 'contact-form-7' ) )
);
$formatter->end_tag( 'p' );
}
$formatter->print();
}
/**
* Displays the service setup form.
*/
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-turnstile-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() ) {
submit_button(
_x( 'Remove Keys', 'API keys', 'contact-form-7' ),
'small', 'reset'
);
} else {
submit_button( __( 'Save Changes', 'contact-form-7' ) );
}
?>
</form>
<?php
}
}

View File

@@ -0,0 +1,209 @@
<?php
/**
* Turnstile module main file
*/
include_once path_join( __DIR__, 'service.php' );
add_action( 'wpcf7_init', 'wpcf7_turnstile_register_service', 35, 0 );
/**
* Registers the Turnstile service.
*/
function wpcf7_turnstile_register_service() {
$integration = WPCF7_Integration::get_instance();
$integration->add_service( 'turnstile',
WPCF7_Turnstile::get_instance()
);
}
add_action( 'wp_enqueue_scripts', 'wpcf7_turnstile_enqueue_scripts', 10, 0 );
/**
* Enqueues the Turnstile script.
*/
function wpcf7_turnstile_enqueue_scripts() {
$service = WPCF7_Turnstile::get_instance();
if ( ! $service->is_active() ) {
return;
}
wp_enqueue_script(
'cloudflare-turnstile',
'https://challenges.cloudflare.com/turnstile/v0/api.js',
array(),
null,
array(
'strategy' => 'async',
)
);
wp_add_inline_script(
'cloudflare-turnstile',
"document.addEventListener( 'wpcf7submit', e => turnstile.reset() );"
);
}
add_action( 'wpcf7_init', 'wpcf7_add_form_tag_turnstile', 10, 0 );
/**
* Registers the Turnstile form-tag type.
*/
function wpcf7_add_form_tag_turnstile() {
$service = WPCF7_Turnstile::get_instance();
if ( ! $service->is_active() ) {
wpcf7_add_form_tag(
'turnstile',
'__return_empty_string',
array(
'display-block' => true,
)
);
return;
}
wpcf7_add_form_tag(
'turnstile',
'wpcf7_turnstile_form_tag_handler',
array(
'display-block' => true,
'singular' => true,
)
);
}
/**
* The Turnstile form-tag handler.
*/
function wpcf7_turnstile_form_tag_handler( $tag ) {
$service = WPCF7_Turnstile::get_instance();
if ( ! $service->is_active() ) {
return;
}
return sprintf(
'<div %s></div>',
wpcf7_format_atts( array(
'class' => 'wpcf7-turnstile cf-turnstile',
'data-sitekey' => $service->get_sitekey(),
'data-response-field-name' => '_wpcf7_turnstile_response',
'data-action' => $tag->get_option(
'action', '[-0-9a-zA-Z_]{1,32}', true
),
'data-appearance' => $tag->get_option(
'appearance', '(always|execute|interaction-only)', true
),
'data-size' => $tag->get_option(
'size', '(normal|flexible|compact)', true
),
'data-theme' => $tag->get_option( 'theme', '(light|dark|auto)', true ),
'data-language' => $tag->get_option( 'language', '[a-z-]{2,5}', true ),
'data-tabindex' => $tag->get_option( 'tabindex', 'signed_int', true ),
) )
);
}
add_filter( 'wpcf7_form_elements', 'wpcf7_turnstile_prepend_widget', 10, 1 );
/**
* Prepends a Turnstile widget to the form content if the form template
* does not include a Turnstile form-tag.
*/
function wpcf7_turnstile_prepend_widget( $content ) {
$service = WPCF7_Turnstile::get_instance();
if ( ! $service->is_active() ) {
return $content;
}
$contact_form = WPCF7_ContactForm::get_current();
$manager = WPCF7_FormTagsManager::get_instance();
$tags = $contact_form->scan_form_tags( array(
'type' => 'turnstile',
) );
if ( empty( $tags ) ) {
$content = $manager->replace_all( '[turnstile]' ) . "\n\n" . $content;
}
return $content;
}
add_filter( 'wpcf7_spam', 'wpcf7_turnstile_verify_response', 9, 2 );
/**
* Verifies the Turnstile response token.
*
* @param bool $spam The spam/ham status inherited from preceding callbacks.
* @param WPCF7_Submission $submission The submission object.
* @return bool True if the submitter is a bot, false if a human.
*/
function wpcf7_turnstile_verify_response( $spam, $submission ) {
if ( $spam ) {
return $spam;
}
$service = WPCF7_Turnstile::get_instance();
if ( ! $service->is_active() ) {
return $spam;
}
$token = wpcf7_superglobal_post( '_wpcf7_turnstile_response' );
if ( $service->verify( $token ) ) { // Human
$spam = false;
} else { // Bot
$spam = true;
if ( '' === $token ) {
$submission->add_spam_log( array(
'agent' => 'turnstile',
'reason' => __( 'Turnstile token is empty.', 'contact-form-7' ),
) );
} else {
$submission->add_spam_log( array(
'agent' => 'turnstile',
'reason' => __( 'Turnstile validation failed.', 'contact-form-7' ),
) );
}
}
return $spam;
}
add_filter(
'wpcf7_flamingo_inbound_message_parameters',
'wpcf7_flamingo_inbound_message_parameters_turnstile',
10, 1
);
/**
* Passes response data from Turnstile siteverify API to Flamingo.
*/
function wpcf7_flamingo_inbound_message_parameters_turnstile( $params ) {
$meta = null;
if ( $submission = WPCF7_Submission::get_instance() ) {
$meta = $submission->pull( 'turnstile' );
}
if ( isset( $meta ) ) {
$params['meta']['turnstile'] = wp_json_encode( $meta );
}
return $params;
}