Commit realizado el 12:13:52 08-04-2024
This commit is contained in:
215
wp-content/plugins/wpforms-lite/src/Forms/Akismet.php
Normal file
215
wp-content/plugins/wpforms-lite/src/Forms/Akismet.php
Normal file
@@ -0,0 +1,215 @@
|
||||
<?php
|
||||
|
||||
namespace WPForms\Forms;
|
||||
|
||||
use Akismet as AkismetPlugin;
|
||||
|
||||
/**
|
||||
* Class Akismet.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*/
|
||||
class Akismet {
|
||||
|
||||
/**
|
||||
* Is the Akismet plugin installed?
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_installed() {
|
||||
|
||||
return file_exists( WP_PLUGIN_DIR . '/akismet/akismet.php' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the Akismet plugin activated?
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_activated() {
|
||||
|
||||
return is_callable( [ 'Akismet', 'get_api_key' ] ) && is_callable( [ 'Akismet', 'http_post' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the Akismet plugin been configured wih a valid API key?
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_configured() {
|
||||
|
||||
// Akismet will only allow an API key to be saved if it is a valid key.
|
||||
// We can assume that if there is an API key saved, it is valid.
|
||||
return self::is_activated() && ! empty( AkismetPlugin::get_api_key() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of field types that are allowed to be sent to Akismet.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @return array List of field types that are allowed to be sent to Akismet
|
||||
*/
|
||||
private function get_field_type_allowlist() {
|
||||
|
||||
$field_type_allowlist = [
|
||||
'text',
|
||||
'textarea',
|
||||
'name',
|
||||
'email',
|
||||
'phone',
|
||||
'address',
|
||||
'url',
|
||||
'richtext',
|
||||
];
|
||||
|
||||
/**
|
||||
* Filters the field types that are allowed to be sent to Akismet.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @param array $field_type_allowlist Field types allowed to be sent to Akismet.
|
||||
*/
|
||||
return (array) apply_filters( 'wpforms_forms_akismet_get_field_type_allowlist', $field_type_allowlist );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entry data to be sent to Akismet.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @param array $fields Field data for the current form.
|
||||
* @param array $entry Entry data.
|
||||
*
|
||||
* @return array $entry_data Entry data to be sent to Akismet.
|
||||
*/
|
||||
private function get_entry_data( $fields, $entry ) {
|
||||
|
||||
$field_type_allowlist = $this->get_field_type_allowlist();
|
||||
$entry_data = [];
|
||||
$entry_content = [];
|
||||
|
||||
foreach ( $fields as $field_id => $field ) {
|
||||
$field_type = $field['type'];
|
||||
|
||||
if ( ! in_array( $field_type, $field_type_allowlist, true ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$field_content = $this->get_field_content( $field, $entry, $field_id );
|
||||
|
||||
if ( ! isset( $entry_data[ $field_type ] ) && in_array( $field_type, [ 'name', 'email', 'url' ], true ) ) {
|
||||
$entry_data[ $field_type ] = $field_content;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$entry_content[] = $field_content;
|
||||
}
|
||||
|
||||
$entry_data['content'] = implode( ' ', $entry_content );
|
||||
|
||||
return $entry_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get field content.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*
|
||||
* @param array $field Field data.
|
||||
* @param array $entry Entry data.
|
||||
* @param int $field_id Field ID.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_field_content( $field, $entry, $field_id ) {
|
||||
|
||||
if ( ! isset( $entry['fields'][ $field_id ] ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( ! is_array( $entry['fields'][ $field_id ] ) ) {
|
||||
return (string) $entry['fields'][ $field_id ];
|
||||
}
|
||||
|
||||
if ( ! empty( $field['type'] ) && $field['type'] === 'email' && ! empty( $entry['fields'][ $field_id ]['primary'] ) ) {
|
||||
return (string) $entry['fields'][ $field_id ]['primary'];
|
||||
}
|
||||
|
||||
return implode( ' ', $entry['fields'][ $field_id ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the entry marked as spam by Akismet?
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @param array $form_data Form data for the current form.
|
||||
* @param array $entry Entry data for the current entry.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function entry_is_spam( $form_data, $entry ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
|
||||
|
||||
$entry_data = $this->get_entry_data( $form_data['fields'], $entry );
|
||||
$request = [
|
||||
'blog' => get_option( 'home' ),
|
||||
'user_ip' => wpforms_is_collecting_ip_allowed( $form_data ) ? wpforms_get_ip() : null,
|
||||
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
'user_agent' => isset( $_SERVER['HTTP_USER_AGENT'] ) ? wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) : null,
|
||||
'referrer' => wp_get_referer() ? wp_get_referer() : null,
|
||||
// phpcs:enable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
'permalink' => wpforms_current_url(),
|
||||
'comment_type' => 'contact-form',
|
||||
'comment_author' => isset( $entry_data['name'] ) ? $entry_data['name'] : '',
|
||||
'comment_author_email' => isset( $entry_data['email'] ) ? $entry_data['email'] : '',
|
||||
'comment_author_url' => isset( $entry_data['url'] ) ? $entry_data['url'] : '',
|
||||
'comment_content' => isset( $entry_data['content'] ) ? $entry_data['content'] : '',
|
||||
'blog_lang' => get_locale(),
|
||||
'blog_charset' => get_bloginfo( 'charset' ),
|
||||
'user_role' => AkismetPlugin::get_user_roles( get_current_user_id() ),
|
||||
'honypot_field_name' => 'wpforms["hp"]',
|
||||
];
|
||||
|
||||
// If we are on a form preview page, tell Akismet that this is a test submission.
|
||||
if ( wpforms()->get( 'preview' )->is_preview_page() ) {
|
||||
$request['is_test'] = true;
|
||||
}
|
||||
|
||||
$response = AkismetPlugin::http_post( build_query( $request ), 'comment-check' );
|
||||
|
||||
return ! empty( $response ) && isset( $response[1] ) && 'true' === trim( $response[1] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate entry.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @param array $form_data Form data for the current form.
|
||||
* @param array $entry Entry data for the current entry.
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
public function validate( array $form_data, array $entry ) {
|
||||
|
||||
// If Akismet is turned on in form settings, is activated, is configured and the entry is spam.
|
||||
if (
|
||||
! empty( $form_data['settings']['akismet'] ) &&
|
||||
self::is_configured() &&
|
||||
$this->entry_is_spam( $form_data, $entry )
|
||||
) {
|
||||
// This string is being logged not printed, so it does not need to be translatable.
|
||||
return esc_html__( 'Anti-spam verification failed, please try again later.', 'wpforms-lite' );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace WPForms\Forms\Fields\Base;
|
||||
|
||||
use WPForms_Field;
|
||||
|
||||
/**
|
||||
* Field's Frontend base class.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
class Frontend {
|
||||
|
||||
/**
|
||||
* Instance of the main WPForms_Field_{something} class.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @var WPForms_Field
|
||||
*/
|
||||
protected $field_obj;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @param WPForms_Field $field_obj Instance of the WPForms_Field_{something} class.
|
||||
*/
|
||||
public function __construct( $field_obj ) {
|
||||
|
||||
$this->field_obj = $field_obj;
|
||||
|
||||
$this->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
public function init() {
|
||||
|
||||
$this->hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
protected function hooks() {
|
||||
}
|
||||
}
|
@@ -0,0 +1,562 @@
|
||||
<?php
|
||||
|
||||
namespace WPForms\Forms\Fields\PaymentCheckbox;
|
||||
|
||||
/**
|
||||
* Checkbox payment field.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*/
|
||||
class Field extends \WPForms_Field {
|
||||
|
||||
/**
|
||||
* Primary class constructor.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*/
|
||||
public function init() {
|
||||
|
||||
// Define field type information.
|
||||
$this->name = esc_html__( 'Checkbox Items', 'wpforms-lite' );
|
||||
$this->keywords = esc_html__( 'product, store, ecommerce, pay, payment', 'wpforms-lite' );
|
||||
$this->type = 'payment-checkbox';
|
||||
$this->icon = 'fa-check-square-o';
|
||||
$this->order = 50;
|
||||
$this->group = 'payment';
|
||||
$this->defaults = [
|
||||
1 => [
|
||||
'label' => esc_html__( 'First Item', 'wpforms-lite' ),
|
||||
'value' => '10',
|
||||
'image' => '',
|
||||
'icon' => '',
|
||||
'icon_style' => '',
|
||||
'default' => '',
|
||||
],
|
||||
2 => [
|
||||
'label' => esc_html__( 'Second Item', 'wpforms-lite' ),
|
||||
'value' => '25',
|
||||
'image' => '',
|
||||
'icon' => '',
|
||||
'icon_style' => '',
|
||||
'default' => '',
|
||||
],
|
||||
3 => [
|
||||
'label' => esc_html__( 'Third Item', 'wpforms-lite' ),
|
||||
'value' => '50',
|
||||
'image' => '',
|
||||
'icon' => '',
|
||||
'icon_style' => '',
|
||||
'default' => '',
|
||||
],
|
||||
];
|
||||
|
||||
$this->hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register hooks.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
private function hooks() {
|
||||
|
||||
// Customize HTML field values.
|
||||
add_filter( 'wpforms_html_field_value', [ $this, 'field_html_value' ], 10, 4 );
|
||||
|
||||
// Define additional field properties.
|
||||
add_filter( "wpforms_field_properties_{$this->type}", [ $this, 'field_properties' ], 5, 3 );
|
||||
|
||||
// This field requires fieldset+legend instead of the field label.
|
||||
add_filter( "wpforms_frontend_modern_is_field_requires_fieldset_{$this->type}", '__return_true', PHP_INT_MAX, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Define additional field properties.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $properties Field properties.
|
||||
* @param array $field Field settings.
|
||||
* @param array $form_data Form data and settings.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function field_properties( $properties, $field, $form_data ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.MaxExceeded
|
||||
|
||||
// Define data.
|
||||
$form_id = absint( $form_data['id'] );
|
||||
$field_id = absint( $field['id'] );
|
||||
$choices = $field['choices'];
|
||||
|
||||
// Remove primary input.
|
||||
unset( $properties['inputs']['primary'] );
|
||||
|
||||
// Set input container (ul) properties.
|
||||
$properties['input_container'] = [
|
||||
'class' => [],
|
||||
'data' => [],
|
||||
'attr' => [],
|
||||
'id' => "wpforms-{$form_id}-field_{$field_id}",
|
||||
];
|
||||
|
||||
// Set input properties.
|
||||
foreach ( $choices as $key => $choice ) {
|
||||
|
||||
// Choice labels should not be left blank, but if they are we
|
||||
// provide a basic value.
|
||||
$label = $choice['label'];
|
||||
|
||||
if ( $label === '' ) {
|
||||
if ( 1 === count( $choices ) ) {
|
||||
$label = esc_html__( 'Checked', 'wpforms-lite' );
|
||||
} else {
|
||||
/* translators: %s - item number. */
|
||||
$label = sprintf( esc_html__( 'Item %s', 'wpforms-lite' ), $key );
|
||||
}
|
||||
}
|
||||
|
||||
$properties['inputs'][ $key ] = [
|
||||
'container' => [
|
||||
'attr' => [],
|
||||
'class' => [ "choice-{$key}" ],
|
||||
'data' => [],
|
||||
'id' => '',
|
||||
],
|
||||
'label' => [
|
||||
'attr' => [
|
||||
'for' => "wpforms-{$form_id}-field_{$field_id}_{$key}",
|
||||
],
|
||||
'class' => [ 'wpforms-field-label-inline' ],
|
||||
'data' => [],
|
||||
'id' => '',
|
||||
'text' => $label,
|
||||
],
|
||||
'attr' => [
|
||||
'name' => "wpforms[fields][{$field_id}][]",
|
||||
'value' => $key,
|
||||
],
|
||||
'class' => [ 'wpforms-payment-price' ],
|
||||
'data' => [
|
||||
'amount' => wpforms_format_amount( wpforms_sanitize_amount( $choice['value'] ) ),
|
||||
],
|
||||
'id' => "wpforms-{$form_id}-field_{$field_id}_{$key}",
|
||||
'icon' => isset( $choice['icon'] ) ? $choice['icon'] : '',
|
||||
'icon_style' => isset( $choice['icon_style'] ) ? $choice['icon_style'] : '',
|
||||
'image' => isset( $choice['image'] ) ? $choice['image'] : '',
|
||||
'required' => ! empty( $field['required'] ) ? 'required' : '',
|
||||
'default' => isset( $choice['default'] ),
|
||||
];
|
||||
}
|
||||
|
||||
// Required class for pagebreak validation.
|
||||
if ( ! empty( $field['required'] ) ) {
|
||||
$properties['input_container']['class'][] = 'wpforms-field-required';
|
||||
}
|
||||
|
||||
// Custom properties if image choices are enabled.
|
||||
if ( ! empty( $field['choices_images'] ) ) {
|
||||
|
||||
$properties['input_container']['class'][] = 'wpforms-image-choices';
|
||||
$properties['input_container']['class'][] = 'wpforms-image-choices-' . sanitize_html_class( $field['choices_images_style'] );
|
||||
|
||||
foreach ( $properties['inputs'] as $key => $inputs ) {
|
||||
$properties['inputs'][ $key ]['container']['class'][] = 'wpforms-image-choices-item';
|
||||
|
||||
if ( in_array( $field['choices_images_style'], [ 'modern', 'classic' ], true ) ) {
|
||||
$properties['inputs'][ $key ]['class'][] = 'wpforms-screen-reader-element';
|
||||
}
|
||||
}
|
||||
} elseif ( ! empty( $field['choices_icons'] ) ) {
|
||||
$properties = wpforms()->get( 'icon_choices' )->field_properties( $properties, $field );
|
||||
}
|
||||
|
||||
// Add selected class for choices with defaults.
|
||||
foreach ( $properties['inputs'] as $key => $inputs ) {
|
||||
if ( ! empty( $inputs['default'] ) ) {
|
||||
$properties['inputs'][ $key ]['container']['class'][] = 'wpforms-selected';
|
||||
}
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get field populated single property value.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param string $raw_value Value from a GET param, always a string.
|
||||
* @param string $input Represent a subfield inside the field. May be empty.
|
||||
* @param array $properties Field properties.
|
||||
* @param array $field Current field specific data.
|
||||
*
|
||||
* @return array Modified field properties.
|
||||
*/
|
||||
protected function get_field_populated_single_property_value( $raw_value, $input, $properties, $field ) {
|
||||
/*
|
||||
* When the form is submitted we get only choice values from the Fallback.
|
||||
* As payment-checkbox (checkboxes) field doesn't support 'show_values' option -
|
||||
* we should transform that into label to check against using general logic in parent method.
|
||||
*/
|
||||
|
||||
if (
|
||||
! is_string( $raw_value ) ||
|
||||
empty( $field['choices'] ) ||
|
||||
! is_array( $field['choices'] )
|
||||
) {
|
||||
return $properties;
|
||||
}
|
||||
|
||||
// The form submits only the sum, so shortcut for Dynamic.
|
||||
if ( ! is_numeric( $raw_value ) ) {
|
||||
return parent::get_field_populated_single_property_value( $raw_value, $input, $properties, $field );
|
||||
}
|
||||
|
||||
$get_value = wpforms_format_amount( wpforms_sanitize_amount( $raw_value ) );
|
||||
|
||||
foreach ( $field['choices'] as $choice ) {
|
||||
if (
|
||||
isset( $choice['label'], $choice['value'] ) &&
|
||||
wpforms_format_amount( wpforms_sanitize_amount( $choice['value'] ) ) === $get_value
|
||||
) {
|
||||
$trans_value = $choice['label'];
|
||||
// Stop iterating over choices.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $trans_value ) ) {
|
||||
return $properties;
|
||||
}
|
||||
|
||||
return parent::get_field_populated_single_property_value( $trans_value, $input, $properties, $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Field options panel inside the builder.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $field Field settings.
|
||||
*/
|
||||
public function field_options( $field ) {
|
||||
/*
|
||||
* Basic field options.
|
||||
*/
|
||||
|
||||
// Options open markup.
|
||||
$this->field_option(
|
||||
'basic-options',
|
||||
$field,
|
||||
[
|
||||
'markup' => 'open',
|
||||
]
|
||||
);
|
||||
|
||||
// Label.
|
||||
$this->field_option( 'label', $field );
|
||||
|
||||
// Choices option.
|
||||
$this->field_option( 'choices_payments', $field );
|
||||
|
||||
// Show price after item labels.
|
||||
$fld = $this->field_element(
|
||||
'toggle',
|
||||
$field,
|
||||
[
|
||||
'slug' => 'show_price_after_labels',
|
||||
'value' => isset( $field['show_price_after_labels'] ) ? '1' : '0',
|
||||
'desc' => esc_html__( 'Show price after item labels', 'wpforms-lite' ),
|
||||
'tooltip' => esc_html__( 'Check this option to show price of the item after the label.', 'wpforms-lite' ),
|
||||
],
|
||||
false
|
||||
);
|
||||
$args = [
|
||||
'slug' => 'show_price_after_labels',
|
||||
'content' => $fld,
|
||||
];
|
||||
|
||||
$this->field_element( 'row', $field, $args );
|
||||
|
||||
// Choices Images.
|
||||
$this->field_option( 'choices_images', $field );
|
||||
|
||||
// Choices Images Style (theme).
|
||||
$this->field_option( 'choices_images_style', $field );
|
||||
|
||||
// Choices Icons.
|
||||
$this->field_option( 'choices_icons', $field );
|
||||
|
||||
// Choices Icons Color.
|
||||
$this->field_option( 'choices_icons_color', $field );
|
||||
|
||||
// Choices Icons Size.
|
||||
$this->field_option( 'choices_icons_size', $field );
|
||||
|
||||
// Choices Icons Style.
|
||||
$this->field_option( 'choices_icons_style', $field );
|
||||
|
||||
// Description.
|
||||
$this->field_option( 'description', $field );
|
||||
|
||||
// Required toggle.
|
||||
$this->field_option( 'required', $field );
|
||||
|
||||
// Options close markup.
|
||||
$this->field_option(
|
||||
'basic-options',
|
||||
$field,
|
||||
[
|
||||
'markup' => 'close',
|
||||
]
|
||||
);
|
||||
|
||||
/*
|
||||
* Advanced field options.
|
||||
*/
|
||||
|
||||
// Options open markup.
|
||||
$this->field_option(
|
||||
'advanced-options',
|
||||
$field,
|
||||
[
|
||||
'markup' => 'open',
|
||||
]
|
||||
);
|
||||
|
||||
// Input columns.
|
||||
$this->field_option( 'input_columns', $field );
|
||||
|
||||
// Custom CSS classes.
|
||||
$this->field_option( 'css', $field );
|
||||
|
||||
// Hide label.
|
||||
$this->field_option( 'label_hide', $field );
|
||||
|
||||
// Options close markup.
|
||||
$this->field_option(
|
||||
'advanced-options',
|
||||
$field,
|
||||
[
|
||||
'markup' => 'close',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Field preview inside the builder.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $field Field settings.
|
||||
*/
|
||||
public function field_preview( $field ) {
|
||||
|
||||
// Label.
|
||||
$this->field_preview_option( 'label', $field );
|
||||
|
||||
// Choices.
|
||||
$this->field_preview_option( 'choices', $field );
|
||||
|
||||
// Description.
|
||||
$this->field_preview_option( 'description', $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Field display on the form front-end.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $field Field settings.
|
||||
* @param array $deprecated Deprecated array.
|
||||
* @param array $form_data Form data and settings.
|
||||
*/
|
||||
public function field_display( $field, $deprecated, $form_data ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
|
||||
|
||||
// Define data.
|
||||
$container = $field['properties']['input_container'];
|
||||
$choices = $field['properties']['inputs'];
|
||||
|
||||
printf(
|
||||
'<ul %s>',
|
||||
wpforms_html_attributes( $container['id'], $container['class'], $container['data'], $container['attr'] ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
);
|
||||
|
||||
foreach ( $choices as $key => $choice ) {
|
||||
|
||||
$label = isset( $choice['label']['text'] ) ? $choice['label']['text'] : '';
|
||||
/* translators: %s - item number. */
|
||||
$label = $label !== '' ? $label : sprintf( esc_html__( 'Item %s', 'wpforms-lite' ), $key );
|
||||
$label .= ! empty( $field['show_price_after_labels'] ) && isset( $choice['data']['amount'] ) ? ' - ' . wpforms_format_amount( wpforms_sanitize_amount( $choice['data']['amount'] ), true ) : '';
|
||||
|
||||
printf(
|
||||
'<li %s>',
|
||||
wpforms_html_attributes( $choice['container']['id'], $choice['container']['class'], $choice['container']['data'], $choice['container']['attr'] ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
);
|
||||
|
||||
if ( empty( $field['dynamic_choices'] ) && ! empty( $field['choices_images'] ) ) {
|
||||
|
||||
// Image choices.
|
||||
printf(
|
||||
'<label %s>',
|
||||
wpforms_html_attributes( $choice['label']['id'], $choice['label']['class'], $choice['label']['data'], $choice['label']['attr'] ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
);
|
||||
|
||||
echo '<span class="wpforms-image-choices-image">';
|
||||
|
||||
if ( ! empty( $choice['image'] ) ) {
|
||||
printf(
|
||||
'<img src="%s" alt="%s"%s>',
|
||||
esc_url( $choice['image'] ),
|
||||
esc_attr( $choice['label']['text'] ),
|
||||
! empty( $choice['label']['text'] ) ? ' title="' . esc_attr( $choice['label']['text'] ) . '"' : ''
|
||||
);
|
||||
}
|
||||
|
||||
echo '</span>';
|
||||
|
||||
if ( $field['choices_images_style'] === 'none' ) {
|
||||
echo '<br>';
|
||||
}
|
||||
|
||||
printf(
|
||||
'<input type="checkbox" %s %s %s>',
|
||||
wpforms_html_attributes( $choice['id'], $choice['class'], $choice['data'], $choice['attr'] ), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
esc_attr( $choice['required'] ),
|
||||
checked( '1', $choice['default'], false )
|
||||
);
|
||||
|
||||
echo '<span class="wpforms-image-choices-label">' . wp_kses_post( $label ) . '</span>';
|
||||
|
||||
echo '</label>';
|
||||
|
||||
} elseif ( empty( $field['dynamic_choices'] ) && ! empty( $field['choices_icons'] ) ) {
|
||||
|
||||
// Icon Choices.
|
||||
wpforms()->get( 'icon_choices' )->field_display( $field, $choice, 'checkbox', $label );
|
||||
|
||||
} else {
|
||||
|
||||
// Normal display.
|
||||
printf(
|
||||
'<input type="checkbox" %s %s %s>',
|
||||
wpforms_html_attributes( $choice['id'], $choice['class'], $choice['data'], $choice['attr'] ), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
esc_attr( $choice['required'] ),
|
||||
checked( '1', $choice['default'], false )
|
||||
);
|
||||
|
||||
printf(
|
||||
'<label %s>%s</label>',
|
||||
wpforms_html_attributes( $choice['label']['id'], $choice['label']['class'], $choice['label']['data'], $choice['label']['attr'] ), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
wp_kses_post( $label )
|
||||
);
|
||||
}
|
||||
|
||||
echo '</li>';
|
||||
}
|
||||
|
||||
echo '</ul>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate field on form submit.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param int $field_id Field ID.
|
||||
* @param array $field_submit Array of selected choice IDs.
|
||||
* @param array $form_data Form data and settings.
|
||||
*/
|
||||
public function validate( $field_id, $field_submit, $form_data ) {
|
||||
|
||||
$error = '';
|
||||
|
||||
// Basic required check - If field is marked as required, check for entry data.
|
||||
if ( ! empty( $form_data['fields'][ $field_id ]['required'] ) && empty( $field_submit ) ) {
|
||||
$error = wpforms_get_required_label();
|
||||
}
|
||||
|
||||
if ( ! empty( $field_submit ) ) {
|
||||
foreach ( (array) $field_submit as $checked_choice ) {
|
||||
// Validate that the option selected is real.
|
||||
if ( empty( $form_data['fields'][ $field_id ]['choices'][ (int) $checked_choice ] ) ) {
|
||||
$error = esc_html__( 'Invalid payment option.', 'wpforms-lite' );
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $error ) ) {
|
||||
wpforms()->get( 'process' )->errors[ $form_data['id'] ][ $field_id ] = $error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format and sanitize field.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param int $field_id Field ID.
|
||||
* @param array $field_submit Array of selected choice IDs.
|
||||
* @param array $form_data Form data and settings.
|
||||
*/
|
||||
public function format( $field_id, $field_submit, $form_data ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh, Generic.Metrics.NestingLevel.MaxExceeded
|
||||
|
||||
$field_submit = array_values( (array) $field_submit );
|
||||
$field = $form_data['fields'][ $field_id ];
|
||||
$name = sanitize_text_field( $field['label'] );
|
||||
$amount = 0;
|
||||
$images = [];
|
||||
$choice_values = [];
|
||||
$choice_labels = [];
|
||||
$choice_keys = [];
|
||||
|
||||
if ( ! empty( $field_submit ) ) {
|
||||
foreach ( $field_submit as $choice_checked ) {
|
||||
foreach ( $field['choices'] as $choice_id => $choice ) {
|
||||
// Exit early.
|
||||
if ( (int) $choice_checked !== (int) $choice_id ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = (float) wpforms_sanitize_amount( $choice['value'] );
|
||||
|
||||
// Increase total amount.
|
||||
$amount += $value;
|
||||
|
||||
$value = wpforms_format_amount( $value, true );
|
||||
$choice_label = '';
|
||||
|
||||
if ( ! empty( $choice['label'] ) ) {
|
||||
$choice_label = sanitize_text_field( $choice['label'] );
|
||||
$value = $choice_label . ' - ' . $value;
|
||||
}
|
||||
|
||||
$choice_labels[] = $choice_label;
|
||||
$choice_values[] = $value;
|
||||
$choice_keys[] = $choice_id;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $choice_keys ) && ! empty( $field['choices_images'] ) ) {
|
||||
foreach ( $choice_keys as $choice_key ) {
|
||||
$images[] = ! empty( $field['choices'][ $choice_key ]['image'] ) ? esc_url_raw( $field['choices'][ $choice_key ]['image'] ) : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wpforms()->get( 'process' )->fields[ $field_id ] = [
|
||||
'name' => $name,
|
||||
'value' => implode( "\r\n", $choice_values ),
|
||||
'value_choice' => implode( "\r\n", $choice_labels ),
|
||||
'value_raw' => implode( ',', array_map( 'absint', $field_submit ) ),
|
||||
'amount' => wpforms_format_amount( $amount ),
|
||||
'amount_raw' => $amount,
|
||||
'currency' => wpforms_get_currency(),
|
||||
'images' => $images,
|
||||
'id' => absint( $field_id ),
|
||||
'type' => sanitize_key( $this->type ),
|
||||
];
|
||||
}
|
||||
}
|
@@ -0,0 +1,517 @@
|
||||
<?php
|
||||
|
||||
namespace WPForms\Forms\Fields\PaymentMultiple;
|
||||
|
||||
/**
|
||||
* Radio payment field.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*/
|
||||
class Field extends \WPForms_Field {
|
||||
|
||||
/**
|
||||
* Primary class constructor.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*/
|
||||
public function init() {
|
||||
|
||||
// Define field type information.
|
||||
$this->name = esc_html__( 'Multiple Items', 'wpforms-lite' );
|
||||
$this->keywords = esc_html__( 'product, store, ecommerce, pay, payment', 'wpforms-lite' );
|
||||
$this->type = 'payment-multiple';
|
||||
$this->icon = 'fa-list-ul';
|
||||
$this->order = 50;
|
||||
$this->group = 'payment';
|
||||
$this->defaults = [
|
||||
1 => [
|
||||
'label' => esc_html__( 'First Item', 'wpforms-lite' ),
|
||||
'value' => '10',
|
||||
'icon' => '',
|
||||
'icon_style' => '',
|
||||
'image' => '',
|
||||
'default' => '',
|
||||
],
|
||||
2 => [
|
||||
'label' => esc_html__( 'Second Item', 'wpforms-lite' ),
|
||||
'value' => '25',
|
||||
'icon' => '',
|
||||
'icon_style' => '',
|
||||
'image' => '',
|
||||
'default' => '',
|
||||
],
|
||||
3 => [
|
||||
'label' => esc_html__( 'Third Item', 'wpforms-lite' ),
|
||||
'value' => '50',
|
||||
'icon' => '',
|
||||
'icon_style' => '',
|
||||
'image' => '',
|
||||
'default' => '',
|
||||
],
|
||||
];
|
||||
|
||||
$this->hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register hooks.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
private function hooks() {
|
||||
|
||||
// Customize HTML field values.
|
||||
add_filter( 'wpforms_html_field_value', [ $this, 'field_html_value' ], 10, 4 );
|
||||
|
||||
// Define additional field properties.
|
||||
add_filter( "wpforms_field_properties_{$this->type}", [ $this, 'field_properties' ], 5, 3 );
|
||||
|
||||
// This field requires fieldset+legend instead of the field label.
|
||||
add_filter( "wpforms_frontend_modern_is_field_requires_fieldset_{$this->type}", '__return_true', PHP_INT_MAX, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Define additional field properties.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $properties Field properties.
|
||||
* @param array $field Field settings.
|
||||
* @param array $form_data Form data and settings.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function field_properties( $properties, $field, $form_data ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.MaxExceeded
|
||||
|
||||
// Define data.
|
||||
$form_id = absint( $form_data['id'] );
|
||||
$field_id = absint( $field['id'] );
|
||||
$choices = $field['choices'];
|
||||
|
||||
// Remove primary input.
|
||||
unset( $properties['inputs']['primary'] );
|
||||
|
||||
// Set input container (ul) properties.
|
||||
$properties['input_container'] = [
|
||||
'class' => [],
|
||||
'data' => [],
|
||||
'attr' => [],
|
||||
'id' => "wpforms-{$form_id}-field_{$field_id}",
|
||||
];
|
||||
|
||||
// Set input properties.
|
||||
foreach ( $choices as $key => $choice ) {
|
||||
|
||||
$properties['inputs'][ $key ] = [
|
||||
'container' => [
|
||||
'attr' => [],
|
||||
'class' => [ "choice-{$key}" ],
|
||||
'data' => [],
|
||||
'id' => '',
|
||||
],
|
||||
'label' => [
|
||||
'attr' => [
|
||||
'for' => "wpforms-{$form_id}-field_{$field_id}_{$key}",
|
||||
],
|
||||
'class' => [ 'wpforms-field-label-inline' ],
|
||||
'data' => [],
|
||||
'id' => '',
|
||||
'text' => $choice['label'],
|
||||
],
|
||||
'attr' => [
|
||||
'name' => "wpforms[fields][{$field_id}]",
|
||||
'value' => $key,
|
||||
],
|
||||
'class' => [ 'wpforms-payment-price' ],
|
||||
'data' => [
|
||||
'amount' => wpforms_format_amount( wpforms_sanitize_amount( $choice['value'] ) ),
|
||||
],
|
||||
'id' => "wpforms-{$form_id}-field_{$field_id}_{$key}",
|
||||
'icon' => isset( $choice['icon'] ) ? $choice['icon'] : '',
|
||||
'icon_style' => isset( $choice['icon_style'] ) ? $choice['icon_style'] : '',
|
||||
'image' => isset( $choice['image'] ) ? $choice['image'] : '',
|
||||
'required' => ! empty( $field['required'] ) ? 'required' : '',
|
||||
'default' => isset( $choice['default'] ),
|
||||
];
|
||||
}
|
||||
|
||||
// Required class for pagebreak validation.
|
||||
if ( ! empty( $field['required'] ) ) {
|
||||
$properties['input_container']['class'][] = 'wpforms-field-required';
|
||||
}
|
||||
|
||||
// Custom properties if image choices are enabled.
|
||||
if ( ! empty( $field['choices_images'] ) ) {
|
||||
|
||||
$properties['input_container']['class'][] = 'wpforms-image-choices';
|
||||
$properties['input_container']['class'][] = 'wpforms-image-choices-' . sanitize_html_class( $field['choices_images_style'] );
|
||||
|
||||
foreach ( $properties['inputs'] as $key => $inputs ) {
|
||||
$properties['inputs'][ $key ]['container']['class'][] = 'wpforms-image-choices-item';
|
||||
|
||||
if ( in_array( $field['choices_images_style'], [ 'modern', 'classic' ], true ) ) {
|
||||
$properties['inputs'][ $key ]['class'][] = 'wpforms-screen-reader-element';
|
||||
}
|
||||
}
|
||||
} elseif ( ! empty( $field['choices_icons'] ) ) {
|
||||
$properties = wpforms()->get( 'icon_choices' )->field_properties( $properties, $field );
|
||||
}
|
||||
|
||||
// Add selected class for choices with defaults.
|
||||
foreach ( $properties['inputs'] as $key => $inputs ) {
|
||||
if ( ! empty( $inputs['default'] ) ) {
|
||||
$properties['inputs'][ $key ]['container']['class'][] = 'wpforms-selected';
|
||||
}
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get field populated single property value.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param string $raw_value Value from a GET param, always a string.
|
||||
* @param string $input Represent a subfield inside the field. May be empty.
|
||||
* @param array $properties Field properties.
|
||||
* @param array $field Current field specific data.
|
||||
*
|
||||
* @return array Modified field properties.
|
||||
*/
|
||||
protected function get_field_populated_single_property_value( $raw_value, $input, $properties, $field ) {
|
||||
/*
|
||||
* When the form is submitted we get only values (prices) from the Fallback.
|
||||
* As payment-multiple (radio) field doesn't support 'show_values' option -
|
||||
* we should transform value into label to check against using general logic in parent method.
|
||||
*/
|
||||
|
||||
if (
|
||||
! is_string( $raw_value ) ||
|
||||
empty( $field['choices'] ) ||
|
||||
! is_array( $field['choices'] )
|
||||
) {
|
||||
return $properties;
|
||||
}
|
||||
|
||||
// The form submits only the sum, so shortcut for Dynamic.
|
||||
if ( ! is_numeric( $raw_value ) ) {
|
||||
return parent::get_field_populated_single_property_value( $raw_value, $input, $properties, $field );
|
||||
}
|
||||
|
||||
$get_value = wpforms_format_amount( wpforms_sanitize_amount( $raw_value ) );
|
||||
|
||||
foreach ( $field['choices'] as $choice ) {
|
||||
if (
|
||||
isset( $choice['label'], $choice['value'] ) &&
|
||||
wpforms_format_amount( wpforms_sanitize_amount( $choice['value'] ) ) === $get_value
|
||||
) {
|
||||
$trans_value = $choice['label'];
|
||||
// Stop iterating over choices.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $trans_value ) ) {
|
||||
return $properties;
|
||||
}
|
||||
|
||||
return parent::get_field_populated_single_property_value( $trans_value, $input, $properties, $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Field options panel inside the builder.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $field Field settings.
|
||||
*/
|
||||
public function field_options( $field ) {
|
||||
/*
|
||||
* Basic field options.
|
||||
*/
|
||||
|
||||
// Options open markup.
|
||||
$this->field_option(
|
||||
'basic-options',
|
||||
$field,
|
||||
[
|
||||
'markup' => 'open',
|
||||
]
|
||||
);
|
||||
|
||||
// Label.
|
||||
$this->field_option( 'label', $field );
|
||||
|
||||
// Choices option.
|
||||
$this->field_option( 'choices_payments', $field );
|
||||
|
||||
// Show price after item labels.
|
||||
$fld = $this->field_element(
|
||||
'toggle',
|
||||
$field,
|
||||
[
|
||||
'slug' => 'show_price_after_labels',
|
||||
'value' => isset( $field['show_price_after_labels'] ) ? '1' : '0',
|
||||
'desc' => esc_html__( 'Show price after item labels', 'wpforms-lite' ),
|
||||
'tooltip' => esc_html__( 'Check this option to show price of the item after the label.', 'wpforms-lite' ),
|
||||
],
|
||||
false
|
||||
);
|
||||
$args = [
|
||||
'slug' => 'show_price_after_labels',
|
||||
'content' => $fld,
|
||||
];
|
||||
|
||||
$this->field_element( 'row', $field, $args );
|
||||
|
||||
// Choices Images.
|
||||
$this->field_option( 'choices_images', $field );
|
||||
|
||||
// Choices Images Style (theme).
|
||||
$this->field_option( 'choices_images_style', $field );
|
||||
|
||||
// Choices Icons.
|
||||
$this->field_option( 'choices_icons', $field );
|
||||
|
||||
// Choices Icons Color.
|
||||
$this->field_option( 'choices_icons_color', $field );
|
||||
|
||||
// Choices Icons Size.
|
||||
$this->field_option( 'choices_icons_size', $field );
|
||||
|
||||
// Choices Icons Style.
|
||||
$this->field_option( 'choices_icons_style', $field );
|
||||
|
||||
// Description.
|
||||
$this->field_option( 'description', $field );
|
||||
|
||||
// Required toggle.
|
||||
$this->field_option( 'required', $field );
|
||||
|
||||
// Options close markup.
|
||||
$this->field_option(
|
||||
'basic-options',
|
||||
$field,
|
||||
[
|
||||
'markup' => 'close',
|
||||
]
|
||||
);
|
||||
|
||||
/*
|
||||
* Advanced field options.
|
||||
*/
|
||||
|
||||
// Options open markup.
|
||||
$this->field_option(
|
||||
'advanced-options',
|
||||
$field,
|
||||
[
|
||||
'markup' => 'open',
|
||||
]
|
||||
);
|
||||
|
||||
// Input columns.
|
||||
$this->field_option( 'input_columns', $field );
|
||||
|
||||
// Custom CSS classes.
|
||||
$this->field_option( 'css', $field );
|
||||
|
||||
// Hide label.
|
||||
$this->field_option( 'label_hide', $field );
|
||||
|
||||
// Options close markup.
|
||||
$this->field_option(
|
||||
'advanced-options',
|
||||
$field,
|
||||
[
|
||||
'markup' => 'close',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Field preview inside the builder.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $field Field settings.
|
||||
*/
|
||||
public function field_preview( $field ) {
|
||||
|
||||
// Label.
|
||||
$this->field_preview_option( 'label', $field );
|
||||
|
||||
// Choices.
|
||||
$this->field_preview_option( 'choices', $field );
|
||||
|
||||
// Description.
|
||||
$this->field_preview_option( 'description', $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Field display on the form front-end.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $field Field settings.
|
||||
* @param array $deprecated Deprecated array.
|
||||
* @param array $form_data Form data and settings.
|
||||
*/
|
||||
public function field_display( $field, $deprecated, $form_data ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
|
||||
|
||||
// Define data.
|
||||
$container = $field['properties']['input_container'];
|
||||
$choices = $field['properties']['inputs'];
|
||||
|
||||
printf(
|
||||
'<ul %s>',
|
||||
wpforms_html_attributes( $container['id'], $container['class'], $container['data'], $container['attr'] ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
);
|
||||
|
||||
foreach ( $choices as $key => $choice ) {
|
||||
|
||||
$label = isset( $choice['label']['text'] ) ? $choice['label']['text'] : '';
|
||||
/* translators: %s - item number. */
|
||||
$label = $label !== '' ? $label : sprintf( esc_html__( 'Item %s', 'wpforms-lite' ), $key );
|
||||
$label .= ! empty( $field['show_price_after_labels'] ) && isset( $choice['data']['amount'] ) ? ' - ' . wpforms_format_amount( wpforms_sanitize_amount( $choice['data']['amount'] ), true ) : '';
|
||||
|
||||
printf(
|
||||
'<li %s>',
|
||||
wpforms_html_attributes( $choice['container']['id'], $choice['container']['class'], $choice['container']['data'], $choice['container']['attr'] ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
);
|
||||
|
||||
if ( empty( $field['dynamic_choices'] ) && ! empty( $field['choices_images'] ) ) {
|
||||
|
||||
// Image choices.
|
||||
printf(
|
||||
'<label %s>',
|
||||
wpforms_html_attributes( $choice['label']['id'], $choice['label']['class'], $choice['label']['data'], $choice['label']['attr'] ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
);
|
||||
|
||||
echo '<span class="wpforms-image-choices-image">';
|
||||
|
||||
if ( ! empty( $choice['image'] ) ) {
|
||||
printf(
|
||||
'<img src="%s" alt="%s"%s>',
|
||||
esc_url( $choice['image'] ),
|
||||
esc_attr( $choice['label']['text'] ),
|
||||
! empty( $choice['label']['text'] ) ? ' title="' . esc_attr( $choice['label']['text'] ) . '"' : ''
|
||||
);
|
||||
}
|
||||
|
||||
echo '</span>';
|
||||
|
||||
if ( $field['choices_images_style'] === 'none' ) {
|
||||
echo '<br>';
|
||||
}
|
||||
|
||||
printf(
|
||||
'<input type="radio" %s %s %s>',
|
||||
wpforms_html_attributes( $choice['id'], $choice['class'], $choice['data'], $choice['attr'] ), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
esc_attr( $choice['required'] ),
|
||||
checked( '1', $choice['default'], false )
|
||||
);
|
||||
|
||||
echo '<span class="wpforms-image-choices-label">' . wp_kses_post( $label ) . '</span>';
|
||||
|
||||
echo '</label>';
|
||||
|
||||
} elseif ( empty( $field['dynamic_choices'] ) && ! empty( $field['choices_icons'] ) ) {
|
||||
|
||||
// Icon Choices.
|
||||
wpforms()->get( 'icon_choices' )->field_display( $field, $choice, 'radio', $label );
|
||||
|
||||
} else {
|
||||
|
||||
// Normal display.
|
||||
printf(
|
||||
'<input type="radio" %s %s %s>',
|
||||
wpforms_html_attributes( $choice['id'], $choice['class'], $choice['data'], $choice['attr'] ), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
esc_attr( $choice['required'] ),
|
||||
checked( '1', $choice['default'], false )
|
||||
);
|
||||
|
||||
printf(
|
||||
'<label %s>%s</label>',
|
||||
wpforms_html_attributes( $choice['label']['id'], $choice['label']['class'], $choice['label']['data'], $choice['label']['attr'] ), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
wp_kses_post( $label )
|
||||
);
|
||||
}
|
||||
|
||||
echo '</li>';
|
||||
}
|
||||
|
||||
echo '</ul>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate field on form submit.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param int $field_id Field ID.
|
||||
* @param array $field_submit Submitted form data.
|
||||
* @param array $form_data Form data and settings.
|
||||
*/
|
||||
public function validate( $field_id, $field_submit, $form_data ) {
|
||||
|
||||
// Basic required check - If field is marked as required, check for entry data.
|
||||
if ( ! empty( $form_data['fields'][ $field_id ]['required'] ) && empty( $field_submit ) ) {
|
||||
|
||||
wpforms()->get( 'process' )->errors[ $form_data['id'] ][ $field_id ] = wpforms_get_required_label();
|
||||
}
|
||||
|
||||
// Validate that the option selected is real.
|
||||
if ( ! empty( $field_submit ) && empty( $form_data['fields'][ $field_id ]['choices'][ $field_submit ] ) ) {
|
||||
wpforms()->get( 'process' )->errors[ $form_data['id'] ][ $field_id ] = esc_html__( 'Invalid payment option.', 'wpforms-lite' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format and sanitize field.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param int $field_id Field ID.
|
||||
* @param string $field_submit Submitted form data.
|
||||
* @param array $form_data Form data and settings.
|
||||
*/
|
||||
public function format( $field_id, $field_submit, $form_data ) {
|
||||
|
||||
$field = $form_data['fields'][ $field_id ];
|
||||
$name = sanitize_text_field( $field['label'] );
|
||||
$value = '';
|
||||
$amount = 0;
|
||||
$choice_label = '';
|
||||
$image = '';
|
||||
|
||||
if ( ! empty( $field_submit ) && ! empty( $field['choices'][ $field_submit ] ) ) {
|
||||
|
||||
$amount = wpforms_sanitize_amount( $field['choices'][ $field_submit ]['value'] );
|
||||
$value = wpforms_format_amount( $amount, true );
|
||||
|
||||
if ( ! empty( $field['choices'][ $field_submit ]['label'] ) ) {
|
||||
$choice_label = sanitize_text_field( $field['choices'][ $field_submit ]['label'] );
|
||||
$value = $choice_label . ' - ' . $value;
|
||||
}
|
||||
|
||||
if ( ! empty( $field['choices_images'] ) ) {
|
||||
$image = ! empty( $field['choices'][ $field_submit ]['image'] ) ? esc_url_raw( $field['choices'][ $field_submit ]['image'] ) : '';
|
||||
}
|
||||
}
|
||||
|
||||
wpforms()->get( 'process' )->fields[ $field_id ] = [
|
||||
'name' => $name,
|
||||
'value' => $value,
|
||||
'value_choice' => $choice_label,
|
||||
'value_raw' => sanitize_text_field( $field_submit ),
|
||||
'amount' => wpforms_format_amount( $amount ),
|
||||
'amount_raw' => $amount,
|
||||
'currency' => wpforms_get_currency(),
|
||||
'image' => $image,
|
||||
'id' => absint( $field_id ),
|
||||
'type' => sanitize_key( $this->type ),
|
||||
];
|
||||
}
|
||||
}
|
@@ -0,0 +1,620 @@
|
||||
<?php
|
||||
|
||||
namespace WPForms\Forms\Fields\PaymentSelect;
|
||||
|
||||
/**
|
||||
* Dropdown payment field.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*/
|
||||
class Field extends \WPForms_Field {
|
||||
|
||||
/**
|
||||
* Classic (old) style.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const STYLE_CLASSIC = 'classic';
|
||||
|
||||
/**
|
||||
* Modern style.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const STYLE_MODERN = 'modern';
|
||||
|
||||
/**
|
||||
* Primary class constructor.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*/
|
||||
public function init() {
|
||||
|
||||
// Define field type information.
|
||||
$this->name = esc_html__( 'Dropdown Items', 'wpforms-lite' );
|
||||
$this->keywords = esc_html__( 'product, store, ecommerce, pay, payment', 'wpforms-lite' );
|
||||
$this->type = 'payment-select';
|
||||
$this->icon = 'fa-caret-square-o-down';
|
||||
$this->order = 70;
|
||||
$this->group = 'payment';
|
||||
$this->defaults = [
|
||||
1 => [
|
||||
'label' => esc_html__( 'First Item', 'wpforms-lite' ),
|
||||
'value' => '10',
|
||||
'default' => '',
|
||||
],
|
||||
2 => [
|
||||
'label' => esc_html__( 'Second Item', 'wpforms-lite' ),
|
||||
'value' => '25',
|
||||
'default' => '',
|
||||
],
|
||||
3 => [
|
||||
'label' => esc_html__( 'Third Item', 'wpforms-lite' ),
|
||||
'value' => '50',
|
||||
'default' => '',
|
||||
],
|
||||
];
|
||||
|
||||
$this->hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register hooks.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*/
|
||||
private function hooks() {
|
||||
|
||||
// Define additional field properties.
|
||||
add_filter( "wpforms_field_properties_{$this->type}", [ $this, 'field_properties' ], 5, 3 );
|
||||
|
||||
// Form frontend CSS enqueues.
|
||||
add_action( 'wpforms_frontend_css', [ $this, 'enqueue_frontend_css' ] );
|
||||
|
||||
// Form frontend JS enqueues.
|
||||
add_action( 'wpforms_frontend_js', [ $this, 'enqueue_frontend_js' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Define additional field properties.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $properties Field properties.
|
||||
* @param array $field Field settings.
|
||||
* @param array $form_data Form data and settings.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function field_properties( $properties, $field, $form_data ) {
|
||||
|
||||
// Remove primary input.
|
||||
unset( $properties['inputs']['primary'] );
|
||||
|
||||
// Define data.
|
||||
$form_id = absint( $form_data['id'] );
|
||||
$field_id = absint( $field['id'] );
|
||||
$choices = $field['choices'];
|
||||
|
||||
// Set options container (<select>) properties.
|
||||
$properties['input_container'] = [
|
||||
'class' => [ 'wpforms-payment-price' ],
|
||||
'data' => [],
|
||||
'id' => "wpforms-{$form_id}-field_{$field_id}",
|
||||
'attr' => [
|
||||
'name' => "wpforms[fields][{$field_id}]",
|
||||
],
|
||||
];
|
||||
|
||||
// Set properties.
|
||||
foreach ( $choices as $key => $choice ) {
|
||||
|
||||
$properties['inputs'][ $key ] = [
|
||||
'container' => [
|
||||
'attr' => [],
|
||||
'class' => [ "choice-{$key}" ],
|
||||
'data' => [],
|
||||
'id' => '',
|
||||
],
|
||||
'label' => [
|
||||
'attr' => [
|
||||
'for' => "wpforms-{$form_id}-field_{$field_id}_{$key}",
|
||||
],
|
||||
'class' => [ 'wpforms-field-label-inline' ],
|
||||
'data' => [],
|
||||
'id' => '',
|
||||
'text' => $choice['label'],
|
||||
],
|
||||
'attr' => [
|
||||
'value' => $choice['value'],
|
||||
'data' => [
|
||||
'amount' => wpforms_format_amount( wpforms_sanitize_amount( $choice['value'] ) ),
|
||||
],
|
||||
],
|
||||
'class' => [],
|
||||
'data' => [],
|
||||
'id' => "wpforms-{$form_id}-field_{$field_id}_{$key}",
|
||||
'required' => ! empty( $field['required'] ) ? 'required' : '',
|
||||
'default' => isset( $choice['default'] ),
|
||||
];
|
||||
}
|
||||
|
||||
// Add class that changes the field size.
|
||||
if ( ! empty( $field['size'] ) ) {
|
||||
$properties['input_container']['class'][] = 'wpforms-field-' . esc_attr( $field['size'] );
|
||||
}
|
||||
|
||||
// Required class for pagebreak validation.
|
||||
if ( ! empty( $field['required'] ) ) {
|
||||
$properties['input_container']['class'][] = 'wpforms-field-required';
|
||||
}
|
||||
|
||||
// Add additional class for container.
|
||||
if (
|
||||
! empty( $field['style'] ) &&
|
||||
in_array( $field['style'], [ self::STYLE_CLASSIC, self::STYLE_MODERN ], true )
|
||||
) {
|
||||
$properties['container']['class'][] = "wpforms-field-select-style-{$field['style']}";
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value, that is used to prefill via dynamic or fallback population.
|
||||
* Based on field data and current properties.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param string $raw_value Value from a GET param, always a string.
|
||||
* @param string $input Represent a subfield inside the field. May be empty.
|
||||
* @param array $properties Field properties.
|
||||
* @param array $field Current field specific data.
|
||||
*
|
||||
* @return array Modified field properties.
|
||||
*/
|
||||
protected function get_field_populated_single_property_value( $raw_value, $input, $properties, $field ) {
|
||||
/*
|
||||
* When the form is submitted we get from Fallback only values (choice ID).
|
||||
* As payment-dropdown field doesn't support 'show_values' option -
|
||||
* we should transform value into label to check against using general logic in parent method.
|
||||
*/
|
||||
|
||||
if (
|
||||
! is_string( $raw_value ) ||
|
||||
empty( $field['choices'] ) ||
|
||||
! is_array( $field['choices'] )
|
||||
) {
|
||||
return $properties;
|
||||
}
|
||||
|
||||
// The form submits only the choice ID, so shortcut for Dynamic when we have a label there.
|
||||
if ( ! is_numeric( $raw_value ) ) {
|
||||
return parent::get_field_populated_single_property_value( $raw_value, $input, $properties, $field );
|
||||
}
|
||||
|
||||
if (
|
||||
! empty( $field['choices'][ $raw_value ]['label'] ) &&
|
||||
! empty( $field['choices'][ $raw_value ]['value'] )
|
||||
) {
|
||||
return parent::get_field_populated_single_property_value( $field['choices'][ $raw_value ]['label'], $input, $properties, $field );
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Field options panel inside the builder.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $field Field settings.
|
||||
*/
|
||||
public function field_options( $field ) {
|
||||
/*
|
||||
* Basic field options.
|
||||
*/
|
||||
|
||||
// Options open markup.
|
||||
$this->field_option( 'basic-options', $field, [ 'markup' => 'open' ] );
|
||||
|
||||
// Label.
|
||||
$this->field_option( 'label', $field );
|
||||
|
||||
// Choices option.
|
||||
$this->field_option( 'choices_payments', $field );
|
||||
|
||||
// Show price after item labels.
|
||||
$fld = $this->field_element(
|
||||
'toggle',
|
||||
$field,
|
||||
[
|
||||
'slug' => 'show_price_after_labels',
|
||||
'value' => isset( $field['show_price_after_labels'] ) ? '1' : '0',
|
||||
'desc' => esc_html__( 'Show price after item labels', 'wpforms-lite' ),
|
||||
'tooltip' => esc_html__( 'Check this option to show price of the item after the label.', 'wpforms-lite' ),
|
||||
],
|
||||
false
|
||||
);
|
||||
$args = [
|
||||
'slug' => 'show_price_after_labels',
|
||||
'content' => $fld,
|
||||
];
|
||||
|
||||
$this->field_element( 'row', $field, $args );
|
||||
|
||||
// Description.
|
||||
$this->field_option( 'description', $field );
|
||||
|
||||
// Required toggle.
|
||||
$this->field_option( 'required', $field );
|
||||
|
||||
// Options close markup.
|
||||
$this->field_option( 'basic-options', $field, [ 'markup' => 'close' ] );
|
||||
|
||||
/*
|
||||
* Advanced field options.
|
||||
*/
|
||||
|
||||
// Options open markup.
|
||||
$this->field_option( 'advanced-options', $field, [ 'markup' => 'open' ] );
|
||||
|
||||
// Style.
|
||||
$lbl = $this->field_element(
|
||||
'label',
|
||||
$field,
|
||||
[
|
||||
'slug' => 'style',
|
||||
'value' => esc_html__( 'Style', 'wpforms-lite' ),
|
||||
'tooltip' => esc_html__( 'Classic style is the default one generated by your browser. Modern has a fresh look and displays all selected options in a single row.', 'wpforms-lite' ),
|
||||
],
|
||||
false
|
||||
);
|
||||
|
||||
$fld = $this->field_element(
|
||||
'select',
|
||||
$field,
|
||||
[
|
||||
'slug' => 'style',
|
||||
'value' => ! empty( $field['style'] ) ? $field['style'] : self::STYLE_CLASSIC,
|
||||
'options' => [
|
||||
self::STYLE_CLASSIC => esc_html__( 'Classic', 'wpforms-lite' ),
|
||||
self::STYLE_MODERN => esc_html__( 'Modern', 'wpforms-lite' ),
|
||||
],
|
||||
],
|
||||
false
|
||||
);
|
||||
|
||||
$this->field_element(
|
||||
'row',
|
||||
$field,
|
||||
[
|
||||
'slug' => 'style',
|
||||
'content' => $lbl . $fld,
|
||||
]
|
||||
);
|
||||
|
||||
// Size.
|
||||
$this->field_option( 'size', $field );
|
||||
|
||||
// Placeholder.
|
||||
$this->field_option( 'placeholder', $field );
|
||||
|
||||
// Custom CSS classes.
|
||||
$this->field_option( 'css', $field );
|
||||
|
||||
// Hide label.
|
||||
$this->field_option( 'label_hide', $field );
|
||||
|
||||
// Options close markup.
|
||||
$this->field_option( 'advanced-options', $field, [ 'markup' => 'close' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Field preview inside the builder.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $field Field settings.
|
||||
*/
|
||||
public function field_preview( $field ) {
|
||||
|
||||
// Label.
|
||||
$this->field_preview_option( 'label', $field );
|
||||
|
||||
// Prepare arguments.
|
||||
$args['modern'] = false;
|
||||
|
||||
if (
|
||||
! empty( $field['style'] ) &&
|
||||
$field['style'] === self::STYLE_MODERN
|
||||
) {
|
||||
$args['modern'] = true;
|
||||
$args['class'] = 'choicesjs-select';
|
||||
}
|
||||
|
||||
// Choices.
|
||||
$this->field_preview_option( 'choices', $field, $args );
|
||||
|
||||
// Description.
|
||||
$this->field_preview_option( 'description', $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Field display on the form front-end.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $field Field data and settings.
|
||||
* @param array $deprecated Deprecated array of field attributes.
|
||||
* @param array $form_data Form data and settings.
|
||||
*/
|
||||
public function field_display( $field, $deprecated, $form_data ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.MaxExceeded
|
||||
|
||||
$container = $field['properties']['input_container'];
|
||||
$field_placeholder = ! empty( $field['placeholder'] ) ? $field['placeholder'] : '';
|
||||
$is_modern = ! empty( $field['style'] ) && $field['style'] === self::STYLE_MODERN;
|
||||
$choices = $field['properties']['inputs'];
|
||||
|
||||
if ( ! empty( $field['required'] ) ) {
|
||||
$container['attr']['required'] = 'required';
|
||||
}
|
||||
|
||||
// Add a class for Choices.js initialization.
|
||||
if ( $is_modern ) {
|
||||
$container['class'][] = 'choicesjs-select';
|
||||
|
||||
// Add a size-class to data attribute - it is used when Choices.js is initialized.
|
||||
if ( ! empty( $field['size'] ) ) {
|
||||
$container['data']['size-class'] = 'wpforms-field-row wpforms-field-' . sanitize_html_class( $field['size'] );
|
||||
}
|
||||
|
||||
$container['data']['search-enabled'] = $this->is_choicesjs_search_enabled( count( $choices ) );
|
||||
}
|
||||
|
||||
$has_default = false;
|
||||
|
||||
// Check to see if any of the options were selected by default.
|
||||
foreach ( $choices as $choice ) {
|
||||
if ( ! empty( $choice['default'] ) ) {
|
||||
$has_default = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Fake placeholder for Modern style.
|
||||
if ( $is_modern && empty( $field_placeholder ) ) {
|
||||
$first_choices = reset( $choices );
|
||||
$field_placeholder = $first_choices['label']['text'];
|
||||
$field_placeholder .= ! empty( $field['show_price_after_labels'] ) && isset( $first_choices['attr']['value'] ) ? ' - ' . wpforms_format_amount( wpforms_sanitize_amount( $first_choices['attr']['value'] ), true ) : '';
|
||||
}
|
||||
|
||||
// Preselect default if no other choices were marked as default.
|
||||
printf(
|
||||
'<select %s>',
|
||||
wpforms_html_attributes( $container['id'], $container['class'], $container['data'], $container['attr'] ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
);
|
||||
|
||||
// Optional placeholder.
|
||||
if ( ! empty( $field_placeholder ) ) {
|
||||
printf(
|
||||
'<option value="" class="placeholder" disabled %s>%s</option>',
|
||||
selected( false, $has_default, false ),
|
||||
esc_html( $field_placeholder )
|
||||
);
|
||||
}
|
||||
|
||||
// Format string for option.
|
||||
if ( $is_modern ) {
|
||||
|
||||
// `data-custom-properties` - it's a Choices.js attribite and it store a copy of `data-amount` attribute.
|
||||
$option_format = '<option value="%1$s" data-amount="%2$s" data-custom-properties="%2$s" %3$s>%4$s</option>';
|
||||
|
||||
} else {
|
||||
$option_format = '<option value="%1$s" data-amount="%2$s" %3$s>%4$s</option>';
|
||||
}
|
||||
|
||||
// Build the select options.
|
||||
foreach ( $choices as $key => $choice ) {
|
||||
$amount = wpforms_format_amount( wpforms_sanitize_amount( $choice['attr']['value'] ) );
|
||||
$label = isset( $choice['label']['text'] ) ? $choice['label']['text'] : '';
|
||||
/* translators: %s - item number. */
|
||||
$label = $label !== '' ? $label : sprintf( esc_html__( 'Item %s', 'wpforms-lite' ), $key );
|
||||
$label .= ! empty( $field['show_price_after_labels'] ) && isset( $choice['attr']['value'] ) ? ' - ' . wpforms_format_amount( wpforms_sanitize_amount( $choice['attr']['value'] ), true ) : '';
|
||||
|
||||
printf(
|
||||
$option_format, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
esc_attr( $key ),
|
||||
esc_attr( $amount ),
|
||||
selected( true, ! empty( $choice['default'] ), false ),
|
||||
esc_html( $label )
|
||||
);
|
||||
}
|
||||
|
||||
echo '</select>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate field on form submit.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param int $field_id Field ID.
|
||||
* @param string $field_submit Submitted field value (selected option).
|
||||
* @param array $form_data Form data and settings.
|
||||
*/
|
||||
public function validate( $field_id, $field_submit, $form_data ) {
|
||||
|
||||
// Basic required check - If field is marked as required, check for entry data.
|
||||
if ( ! empty( $form_data['fields'][ $field_id ]['required'] ) && empty( $field_submit ) ) {
|
||||
|
||||
wpforms()->get( 'process' )->errors[ $form_data['id'] ][ $field_id ] = wpforms_get_required_label();
|
||||
}
|
||||
|
||||
// Validate that the option selected is real.
|
||||
if ( ! empty( $field_submit ) && empty( $form_data['fields'][ $field_id ]['choices'][ $field_submit ] ) ) {
|
||||
|
||||
wpforms()->get( 'process' )->errors[ $form_data['id'] ][ $field_id ] = esc_html__( 'Invalid payment option', 'wpforms-lite' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format and sanitize field.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param int $field_id Field ID.
|
||||
* @param string $field_submit Submitted field value (selected option).
|
||||
* @param array $form_data Form data and settings.
|
||||
*/
|
||||
public function format( $field_id, $field_submit, $form_data ) {
|
||||
|
||||
$choice_label = '';
|
||||
$field = $form_data['fields'][ $field_id ];
|
||||
$name = ! empty( $field['label'] ) ? sanitize_text_field( $field['label'] ) : '';
|
||||
|
||||
// Fetch the amount.
|
||||
if ( ! empty( $field['choices'][ $field_submit ]['value'] ) ) {
|
||||
$amount = wpforms_sanitize_amount( $field['choices'][ $field_submit ]['value'] );
|
||||
} else {
|
||||
$amount = 0;
|
||||
}
|
||||
|
||||
$value = wpforms_format_amount( $amount, true );
|
||||
|
||||
if ( empty( $field_submit ) ) {
|
||||
$value = '';
|
||||
} elseif ( ! empty( $field['choices'][ $field_submit ]['label'] ) ) {
|
||||
$choice_label = sanitize_text_field( $field['choices'][ $field_submit ]['label'] );
|
||||
$value = $choice_label . ' - ' . $value;
|
||||
}
|
||||
|
||||
wpforms()->get( 'process' )->fields[ $field_id ] = [
|
||||
'name' => $name,
|
||||
'value' => $value,
|
||||
'value_choice' => $choice_label,
|
||||
'value_raw' => sanitize_text_field( $field_submit ),
|
||||
'amount' => wpforms_format_amount( $amount ),
|
||||
'amount_raw' => $amount,
|
||||
'currency' => wpforms_get_currency(),
|
||||
'id' => absint( $field_id ),
|
||||
'type' => sanitize_key( $this->type ),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Form frontend CSS enqueues.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $forms Forms on the current page.
|
||||
*/
|
||||
public function enqueue_frontend_css( $forms ) {
|
||||
|
||||
$has_modern_select = false;
|
||||
|
||||
foreach ( $forms as $form ) {
|
||||
if ( $this->is_field_style( $form, self::STYLE_MODERN ) ) {
|
||||
$has_modern_select = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $has_modern_select || wpforms()->get( 'frontend' )->assets_global() ) {
|
||||
$min = wpforms_get_min_suffix();
|
||||
|
||||
wp_enqueue_style(
|
||||
'wpforms-choicesjs',
|
||||
WPFORMS_PLUGIN_URL . "assets/css/choices{$min}.css",
|
||||
[],
|
||||
'9.0.1'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Form frontend JS enqueues.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $forms Forms on the current page.
|
||||
*/
|
||||
public function enqueue_frontend_js( $forms ) {
|
||||
|
||||
$has_modern_select = false;
|
||||
|
||||
foreach ( $forms as $form ) {
|
||||
if ( $this->is_field_style( $form, self::STYLE_MODERN ) ) {
|
||||
$has_modern_select = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $has_modern_select || wpforms()->get( 'frontend' )->assets_global() ) {
|
||||
$this->enqueue_choicesjs_once( $forms );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the provided form has a dropdown field with a specified style.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $form Form data.
|
||||
* @param string $style Desired field style.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_field_style( $form, $style ) {
|
||||
|
||||
$is_field_style = false;
|
||||
|
||||
if ( empty( $form['fields'] ) ) {
|
||||
return $is_field_style;
|
||||
}
|
||||
|
||||
foreach ( (array) $form['fields'] as $field ) {
|
||||
|
||||
if (
|
||||
! empty( $field['type'] ) &&
|
||||
$field['type'] === $this->type &&
|
||||
! empty( $field['style'] ) &&
|
||||
sanitize_key( $style ) === $field['style']
|
||||
) {
|
||||
$is_field_style = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $is_field_style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get field name for ajax error message.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param string $name Field name for error triggered.
|
||||
* @param array $field Field settings.
|
||||
* @param array $props List of properties.
|
||||
* @param string $error Error message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function ajax_error_field_name( $name, $field, $props, $error ) {
|
||||
|
||||
if ( ! isset( $field['type'] ) || $field['type'] !== $this->type ) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
return isset( $props['input_container']['attr']['name'] ) ? $props['input_container']['attr']['name'] : '';
|
||||
}
|
||||
}
|
@@ -0,0 +1,471 @@
|
||||
<?php
|
||||
|
||||
namespace WPForms\Forms\Fields\PaymentSingle;
|
||||
|
||||
/**
|
||||
* Single item payment field.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*/
|
||||
class Field extends \WPForms_Field {
|
||||
|
||||
/**
|
||||
* User field format.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const FORMAT_USER = 'user';
|
||||
|
||||
/**
|
||||
* Single field format.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const FORMAT_SINGLE = 'single';
|
||||
|
||||
/**
|
||||
* Hidden field format.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const FORMAT_HIDDEN = 'hidden';
|
||||
|
||||
/**
|
||||
* Primary class constructor.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*/
|
||||
public function init() {
|
||||
|
||||
// Define field type information.
|
||||
$this->name = esc_html__( 'Single Item', 'wpforms-lite' );
|
||||
$this->keywords = esc_html__( 'product, store, ecommerce, pay, payment', 'wpforms-lite' );
|
||||
$this->type = 'payment-single';
|
||||
$this->icon = 'fa-file-o';
|
||||
$this->order = 30;
|
||||
$this->group = 'payment';
|
||||
|
||||
$this->hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Define additional field hooks.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*/
|
||||
private function hooks() {
|
||||
|
||||
// Define additional field properties.
|
||||
add_filter( "wpforms_field_properties_{$this->type}", [ $this, 'field_properties' ], 5, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Define additional field properties.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $properties Field properties.
|
||||
* @param array $field Field settings.
|
||||
* @param array $form_data Form data and settings.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function field_properties( $properties, $field, $form_data ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
|
||||
|
||||
// Basic IDs.
|
||||
$form_id = absint( $form_data['id'] );
|
||||
$field_id = absint( $field['id'] );
|
||||
|
||||
// Set options container (<select>) properties.
|
||||
$properties['input_container'] = [
|
||||
'class' => [ 'wpforms-payment-price' ],
|
||||
'data' => [],
|
||||
'id' => "wpforms-{$form_id}-field_{$field_id}",
|
||||
];
|
||||
|
||||
// User format data and class.
|
||||
$field_format = ! empty( $field['format'] ) ? $field['format'] : self::FORMAT_SINGLE;
|
||||
|
||||
if ( $field_format === self::FORMAT_USER ) {
|
||||
$properties['inputs']['primary']['data']['rule-currency'] = '["$",false]';
|
||||
|
||||
$properties['inputs']['primary']['class'][] = 'wpforms-payment-user-input';
|
||||
}
|
||||
|
||||
$properties['inputs']['primary']['class'][] = 'wpforms-payment-price';
|
||||
|
||||
// Check size.
|
||||
if ( ! empty( $field['size'] ) ) {
|
||||
$properties['inputs']['primary']['class'][] = 'wpforms-field-' . esc_attr( $field['size'] );
|
||||
}
|
||||
|
||||
$required = ! empty( $form_data['fields'][ $field_id ]['required'] );
|
||||
|
||||
if ( $required ) {
|
||||
$properties['inputs']['primary']['data']['rule-required-positive-number'] = true;
|
||||
}
|
||||
|
||||
// Price.
|
||||
if ( ! empty( $field['price'] ) ) {
|
||||
$field_value = wpforms_sanitize_amount( $field['price'] );
|
||||
} elseif ( $required && $field_format === self::FORMAT_SINGLE ) {
|
||||
$field_value = wpforms_format_amount( 0 );
|
||||
} else {
|
||||
$field_value = '';
|
||||
}
|
||||
|
||||
$properties['inputs']['primary']['attr']['value'] = ! empty( $field_value ) ? wpforms_format_amount( $field_value, true ) : $field_value;
|
||||
|
||||
// Single item and hidden format should hide the input field.
|
||||
if ( ! empty( $field['format'] ) && $field['format'] === self::FORMAT_HIDDEN ) {
|
||||
$properties['container']['class'][] = 'wpforms-field-hidden';
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get field populated single property value.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param string $raw_value Value from a GET param, always a string.
|
||||
* @param string $input Represent a subfield inside the field. May be empty.
|
||||
* @param array $properties Field properties.
|
||||
* @param array $field Current field specific data.
|
||||
*
|
||||
* @return array Modified field properties.
|
||||
*/
|
||||
protected function get_field_populated_single_property_value( $raw_value, $input, $properties, $field ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
|
||||
|
||||
if ( ! is_string( $raw_value ) ) {
|
||||
return $properties;
|
||||
}
|
||||
|
||||
// Allow to redefine the value for user-defined price only.
|
||||
$field_format = ! empty( $field['format'] ) ? $field['format'] : self::FORMAT_SINGLE;
|
||||
|
||||
if ( $field_format !== self::FORMAT_USER ) {
|
||||
return $properties;
|
||||
}
|
||||
|
||||
$get_value = stripslashes( sanitize_text_field( $raw_value ) );
|
||||
$get_value = ! empty( $get_value ) ? wpforms_sanitize_amount( $get_value ) : '';
|
||||
$get_value_formatted = ! empty( $get_value ) ? wpforms_format_amount( $get_value ) : '';
|
||||
|
||||
// `primary` by default.
|
||||
if (
|
||||
! empty( $input ) &&
|
||||
isset( $properties['inputs'][ $input ] )
|
||||
) {
|
||||
$properties['inputs'][ $input ]['attr']['value'] = $get_value_formatted;
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Field options panel inside the builder.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $field Field data and settings.
|
||||
*/
|
||||
public function field_options( $field ) {
|
||||
/*
|
||||
* Basic field options.
|
||||
*/
|
||||
|
||||
$this->field_option( 'basic-options', $field, [ 'markup' => 'open' ] );
|
||||
$this->field_option( 'label', $field );
|
||||
$this->field_option( 'description', $field );
|
||||
|
||||
// Item Price.
|
||||
$price = ! empty( $field['price'] ) ? wpforms_format_amount( wpforms_sanitize_amount( $field['price'] ) ) : '';
|
||||
$tooltip = esc_html__( 'Enter the price of the item, without a currency symbol.', 'wpforms-lite' );
|
||||
|
||||
$output = $this->field_element(
|
||||
'label',
|
||||
$field,
|
||||
[
|
||||
'slug' => 'price',
|
||||
'value' => esc_html__( 'Item Price', 'wpforms-lite' ),
|
||||
'tooltip' => $tooltip,
|
||||
],
|
||||
false
|
||||
);
|
||||
|
||||
$output .= $this->field_element(
|
||||
'text',
|
||||
$field,
|
||||
[
|
||||
'slug' => 'price',
|
||||
'value' => $price,
|
||||
'class' => 'wpforms-money-input',
|
||||
'placeholder' => wpforms_format_amount( 0 ),
|
||||
],
|
||||
false
|
||||
);
|
||||
|
||||
$this->field_element(
|
||||
'row',
|
||||
$field,
|
||||
[
|
||||
'slug' => 'price',
|
||||
'content' => $output,
|
||||
]
|
||||
);
|
||||
|
||||
// Item Format option.
|
||||
$format = ! empty( $field['format'] ) ? esc_attr( $field['format'] ) : 'date-time';
|
||||
$tooltip = esc_html__( 'Select the item type.', 'wpforms-lite' );
|
||||
$options = [
|
||||
self::FORMAT_SINGLE => esc_html__( 'Single Item', 'wpforms-lite' ),
|
||||
self::FORMAT_USER => esc_html__( 'User Defined', 'wpforms-lite' ),
|
||||
self::FORMAT_HIDDEN => esc_html__( 'Hidden', 'wpforms-lite' ),
|
||||
];
|
||||
|
||||
$output = $this->field_element(
|
||||
'label',
|
||||
$field,
|
||||
[
|
||||
'slug' => 'format',
|
||||
'value' => esc_html__( 'Item Type', 'wpforms-lite' ),
|
||||
'tooltip' => $tooltip,
|
||||
],
|
||||
false
|
||||
);
|
||||
|
||||
$output .= $this->field_element(
|
||||
'select',
|
||||
$field,
|
||||
[
|
||||
'slug' => 'format',
|
||||
'value' => $format,
|
||||
'options' => $options,
|
||||
],
|
||||
false
|
||||
);
|
||||
|
||||
$this->field_element(
|
||||
'row',
|
||||
$field,
|
||||
[
|
||||
'slug' => 'format',
|
||||
'content' => $output,
|
||||
]
|
||||
);
|
||||
|
||||
$this->field_option( 'required', $field );
|
||||
$this->field_option( 'basic-options', $field, [ 'markup' => 'close' ] );
|
||||
|
||||
/*
|
||||
* Advanced field options.
|
||||
*/
|
||||
|
||||
$this->field_option( 'advanced-options', $field, [ 'markup' => 'open' ] );
|
||||
$this->field_option( 'size', $field );
|
||||
|
||||
$visibility = ! empty( $field['format'] ) && $field['format'] === self::FORMAT_USER ? '' : 'wpforms-hidden';
|
||||
$this->field_option( 'placeholder', $field, [ 'class' => $visibility ] );
|
||||
|
||||
$this->field_option( 'css', $field );
|
||||
$this->field_option( 'label_hide', $field );
|
||||
$this->field_option( 'advanced-options', $field, [ 'markup' => 'close' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Field preview inside the builder.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $field Field data and settings.
|
||||
*/
|
||||
public function field_preview( $field ) {
|
||||
|
||||
$price = ! empty( $field['price'] ) ? wpforms_format_amount( wpforms_sanitize_amount( $field['price'] ), true ) : wpforms_format_amount( 0, true );
|
||||
$placeholder = ! empty( $field['placeholder'] ) ? $field['placeholder'] : wpforms_format_amount( 0 );
|
||||
$format = ! empty( $field['format'] ) ? $field['format'] : self::FORMAT_SINGLE;
|
||||
$value = ! empty( $field['price'] ) ? wpforms_format_amount( wpforms_sanitize_amount( $field['price'] ) ) : '';
|
||||
|
||||
$this->field_preview_option( 'label', $field );
|
||||
|
||||
echo '<div class="format-selected-' . esc_attr( $format ) . ' format-selected">';
|
||||
|
||||
echo '<p class="item-price">';
|
||||
printf(
|
||||
/* translators: %s - price amount. */
|
||||
esc_html__( 'Price: %s', 'wpforms-lite' ),
|
||||
'<span class="price">' . esc_html( $price ) . '</span>'
|
||||
);
|
||||
echo '</p>';
|
||||
|
||||
printf(
|
||||
'<input type="text" placeholder="%s" class="primary-input" value="%s" readonly>',
|
||||
esc_attr( $placeholder ),
|
||||
esc_attr( $value )
|
||||
);
|
||||
|
||||
$this->field_preview_option( 'description', $field );
|
||||
|
||||
echo '<p class="item-price-hidden">';
|
||||
esc_html_e( 'Note: Item type is set to hidden and will not be visible when viewing the form.', 'wpforms-lite' );
|
||||
echo '</p>';
|
||||
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Field display on the form front-end.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $field Field data and settings.
|
||||
* @param array $deprecated Deprecated field attributes.
|
||||
* @param array $form_data Form data and settings.
|
||||
*/
|
||||
public function field_display( $field, $deprecated, $form_data ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
|
||||
|
||||
// Shortcut for easier access.
|
||||
$primary = $field['properties']['inputs']['primary'];
|
||||
|
||||
$field_format = ! empty( $field['format'] ) ? $field['format'] : self::FORMAT_SINGLE;
|
||||
|
||||
// Placeholder attribute is only applicable to password, search, tel, text and url inputs, not hidden.
|
||||
if ( $field_format !== self::FORMAT_USER ) {
|
||||
unset( $primary['attr']['placeholder'] );
|
||||
}
|
||||
|
||||
switch ( $field_format ) {
|
||||
case self::FORMAT_SINGLE:
|
||||
case self::FORMAT_HIDDEN:
|
||||
if ( $field_format === self::FORMAT_SINGLE ) {
|
||||
$price = ! empty( $field['price'] ) ? $field['price'] : 0;
|
||||
|
||||
echo '<div class="wpforms-single-item-price">';
|
||||
printf(
|
||||
/* translators: %s - price amount. */
|
||||
esc_html__( 'Price: %s', 'wpforms-lite' ),
|
||||
'<span class="wpforms-price">' . esc_html( wpforms_format_amount( wpforms_sanitize_amount( $price ), true ) ) . '</span>'
|
||||
);
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
// Primary price field.
|
||||
printf(
|
||||
'<input type="hidden" %s>',
|
||||
wpforms_html_attributes( $primary['id'], $primary['class'], $primary['data'], $primary['attr'] ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
);
|
||||
break;
|
||||
|
||||
case self::FORMAT_USER:
|
||||
printf(
|
||||
'<input type="text" %s>',
|
||||
wpforms_html_attributes( $primary['id'], $primary['class'], $primary['data'], $primary['attr'] ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate field on form submit.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param int $field_id Field ID.
|
||||
* @param string $field_submit Field data submitted by a user.
|
||||
* @param array $form_data Form data and settings.
|
||||
*/
|
||||
public function validate( $field_id, $field_submit, $form_data ) {
|
||||
|
||||
// If field is required, check for data.
|
||||
if (
|
||||
empty( $field_submit ) &&
|
||||
! empty( $form_data['fields'][ $field_id ]['required'] )
|
||||
) {
|
||||
wpforms()->get( 'process' )->errors[ $form_data['id'] ][ $field_id ] = wpforms_get_required_label();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to validate amount or not of the Payment Single item field.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*
|
||||
* @param bool $validate Whether to validate amount or not. Default true.
|
||||
* @param int $field_id Field ID.
|
||||
* @param string $field_submit Field data submitted by a user.
|
||||
* @param array $form_data Form data and settings.
|
||||
*/
|
||||
$validate_amount = apply_filters( 'wpforms_forms_fields_payment_single_field_validate_amount', true, $field_id, $field_submit, $form_data );
|
||||
|
||||
// If field format is not user provided, validate the amount posted.
|
||||
if (
|
||||
! empty( $field_submit ) &&
|
||||
$validate_amount &&
|
||||
$form_data['fields'][ $field_id ]['format'] !== self::FORMAT_USER
|
||||
) {
|
||||
|
||||
$price = wpforms_sanitize_amount( $form_data['fields'][ $field_id ]['price'] );
|
||||
$submit = wpforms_sanitize_amount( $field_submit );
|
||||
|
||||
if ( $price !== $submit ) {
|
||||
wpforms()->get( 'process' )->errors[ $form_data['id'] ][ $field_id ] = esc_html__( 'Amount mismatch', 'wpforms-lite' );
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
! empty( $field_submit ) &&
|
||||
$validate_amount &&
|
||||
$form_data['fields'][ $field_id ]['format'] === self::FORMAT_USER
|
||||
) {
|
||||
$submit = wpforms_sanitize_amount( $field_submit );
|
||||
|
||||
if ( $submit < 0 ) {
|
||||
wpforms()->get( 'process' )->errors[ $form_data['id'] ][ $field_id ] = esc_html__( 'Amount can\'t be negative' , 'wpforms-lite' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format and sanitize field.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param int $field_id Field ID.
|
||||
* @param string $field_submit Field data submitted by a user.
|
||||
* @param array $form_data Form data and settings.
|
||||
*/
|
||||
public function format( $field_id, $field_submit, $form_data ) {
|
||||
|
||||
$field = $form_data['fields'][ $field_id ];
|
||||
$name = ! empty( $field['label'] ) ? sanitize_text_field( $field['label'] ) : '';
|
||||
|
||||
// Only trust the value if the field is user format.
|
||||
if ( $field['format'] === self::FORMAT_USER ) {
|
||||
$amount = wpforms_sanitize_amount( $field_submit );
|
||||
} else {
|
||||
$amount = wpforms_sanitize_amount( $field['price'] );
|
||||
}
|
||||
|
||||
wpforms()->get( 'process' )->fields[ $field_id ] = [
|
||||
'name' => $name,
|
||||
'value' => wpforms_format_amount( $amount, true ),
|
||||
'amount' => wpforms_format_amount( $amount ),
|
||||
'amount_raw' => $amount,
|
||||
'currency' => wpforms_get_currency(),
|
||||
'id' => absint( $field_id ),
|
||||
'type' => sanitize_key( $this->type ),
|
||||
];
|
||||
}
|
||||
}
|
@@ -0,0 +1,304 @@
|
||||
<?php
|
||||
|
||||
namespace WPForms\Forms\Fields\PaymentTotal;
|
||||
|
||||
/**
|
||||
* Total payment field.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*/
|
||||
class Field extends \WPForms_Field {
|
||||
|
||||
/**
|
||||
* Primary class constructor.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*/
|
||||
public function init() {
|
||||
|
||||
// Define field type information.
|
||||
$this->name = esc_html__( 'Total', 'wpforms-lite' );
|
||||
$this->keywords = esc_html__( 'store, ecommerce, pay, payment, sum', 'wpforms-lite' );
|
||||
$this->type = 'payment-total';
|
||||
$this->icon = 'fa-money';
|
||||
$this->order = 110;
|
||||
$this->group = 'payment';
|
||||
|
||||
$this->hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*/
|
||||
private function hooks() {
|
||||
|
||||
// Define additional field properties.
|
||||
add_filter( "wpforms_field_properties_{$this->type}", [ $this, 'field_properties' ], 5, 3 );
|
||||
|
||||
// Recalculate total for a form.
|
||||
add_filter( 'wpforms_process_filter', [ $this, 'calculate_total' ], 10, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Define additional field properties.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $properties Field properties.
|
||||
* @param array $field Field data and settings.
|
||||
* @param array $form_data Form data and settings.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function field_properties( $properties, $field, $form_data ) {
|
||||
|
||||
// Input Primary: initial total is always zero.
|
||||
$properties['inputs']['primary']['attr']['value'] = '0';
|
||||
|
||||
// Input Primary: add class for targeting calculations.
|
||||
$properties['inputs']['primary']['class'][] = 'wpforms-payment-total';
|
||||
|
||||
// Input Primary: add data attribute if total is required.
|
||||
if ( ! empty( $field['required'] ) ) {
|
||||
$properties['inputs']['primary']['data']['rule-required-payment'] = true;
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether current field can be populated dynamically.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $properties Field properties.
|
||||
* @param array $field Current field specific data.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_dynamic_population_allowed( $properties, $field ) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether current field can be populated dynamically.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $properties Field properties.
|
||||
* @param array $field Current field specific data.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_fallback_population_allowed( $properties, $field ) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not trust the posted total since that relies on javascript.
|
||||
*
|
||||
* Instead we re-calculate server side.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $fields List of fields with their data.
|
||||
* @param array $entry Submitted form data.
|
||||
* @param array $form_data Form data and settings.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function calculate_total( $fields, $entry, $form_data ) {
|
||||
|
||||
return self::calculate_total_static( $fields, $entry, $form_data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Static version of calculate_total().
|
||||
*
|
||||
* @since 1.8.4
|
||||
*
|
||||
* @param array $fields List of fields with their data.
|
||||
* @param array $entry Submitted form data.
|
||||
* @param array $form_data Form data and settings.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function calculate_total_static( $fields, $entry, $form_data ) {
|
||||
|
||||
if ( ! is_array( $fields ) ) {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
// At this point we have passed processing and validation, so we know
|
||||
// the amounts in $fields are safe to use.
|
||||
$total = wpforms_get_total_payment( $fields );
|
||||
$amount = wpforms_sanitize_amount( $total );
|
||||
|
||||
foreach ( $fields as $id => $field ) {
|
||||
if ( ! empty( $field['type'] ) && $field['type'] === 'payment-total' ) {
|
||||
$fields[ $id ]['value'] = wpforms_format_amount( $amount, true );
|
||||
$fields[ $id ]['amount'] = wpforms_format_amount( $amount );
|
||||
$fields[ $id ]['amount_raw'] = $amount;
|
||||
}
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Field options panel inside the builder.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $field Field data and settings.
|
||||
*/
|
||||
public function field_options( $field ) {
|
||||
/*
|
||||
* Basic field options.
|
||||
*/
|
||||
|
||||
// Options open markup.
|
||||
$args = [
|
||||
'markup' => 'open',
|
||||
];
|
||||
|
||||
$this->field_option( 'basic-options', $field, $args );
|
||||
|
||||
// Label.
|
||||
$this->field_option( 'label', $field );
|
||||
|
||||
// Description.
|
||||
$this->field_option( 'description', $field );
|
||||
|
||||
// Required toggle.
|
||||
$this->field_option( 'required', $field );
|
||||
|
||||
// Options close markup.
|
||||
$args = [
|
||||
'markup' => 'close',
|
||||
];
|
||||
|
||||
$this->field_option( 'basic-options', $field, $args );
|
||||
|
||||
/*
|
||||
* Advanced field options.
|
||||
*/
|
||||
|
||||
// Options open markup.
|
||||
$args = [
|
||||
'markup' => 'open',
|
||||
];
|
||||
|
||||
$this->field_option( 'advanced-options', $field, $args );
|
||||
|
||||
// Custom CSS classes.
|
||||
$this->field_option( 'css', $field );
|
||||
|
||||
// Hide label.
|
||||
$this->field_option( 'label_hide', $field );
|
||||
|
||||
// Options close markup.
|
||||
$args = [
|
||||
'markup' => 'close',
|
||||
];
|
||||
|
||||
$this->field_option( 'advanced-options', $field, $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Field preview inside the builder.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $field Field data and settings.
|
||||
*/
|
||||
public function field_preview( $field ) {
|
||||
|
||||
// Label.
|
||||
$this->field_preview_option( 'label', $field );
|
||||
|
||||
// Primary field.
|
||||
echo '<div>' . esc_html( wpforms_format_amount( 0, true ) ) . '</div>';
|
||||
|
||||
// Description.
|
||||
$this->field_preview_option( 'description', $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Field display on the form front-end.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $field Field data and settings.
|
||||
* @param array $deprecated Deprecated, not used parameter.
|
||||
* @param array $form_data Form data and settings.
|
||||
*/
|
||||
public function field_display( $field, $deprecated, $form_data ) {
|
||||
|
||||
$primary = $field['properties']['inputs']['primary'];
|
||||
$type = ! empty( $field['required'] ) ? 'text' : 'hidden';
|
||||
$attrs = $primary['attr'];
|
||||
|
||||
if ( ! empty( $field['required'] ) ) {
|
||||
$attrs['style'] = 'position:absolute!important;clip:rect(0,0,0,0)!important;height:1px!important;width:1px!important;border:0!important;overflow:hidden!important;padding:0!important;margin:0!important;';
|
||||
$attrs['readonly'] = 'readonly';
|
||||
}
|
||||
|
||||
// This displays the total the user sees.
|
||||
echo '<div class="wpforms-payment-total">' . esc_html( wpforms_format_amount( 0, true ) ) . '</div>';
|
||||
|
||||
// Hidden input for processing.
|
||||
printf(
|
||||
'<input type="%s" %s>',
|
||||
esc_attr( $type ),
|
||||
wpforms_html_attributes( $primary['id'], $primary['class'], $primary['data'], $attrs ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate field on form submit.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param int $field_id Field ID.
|
||||
* @param string $field_submit Field value submitted by a user.
|
||||
* @param array $form_data Form data and settings.
|
||||
*/
|
||||
public function validate( $field_id, $field_submit, $form_data ) {
|
||||
|
||||
// Basic required check - If field is marked as required, check for entry data.
|
||||
if ( ! empty( $form_data['fields'][ $field_id ]['required'] ) && ( empty( $field_submit ) || wpforms_sanitize_amount( $field_submit ) <= 0 ) ) {
|
||||
wpforms()->get( 'process' )->errors[ $form_data['id'] ][ $field_id ] = esc_html__( 'Payment is required.', 'wpforms-lite' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format and sanitize field.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param int $field_id Field ID.
|
||||
* @param string $field_submit Field value submitted by a user.
|
||||
* @param array $form_data Form data and settings.
|
||||
*/
|
||||
public function format( $field_id, $field_submit, $form_data ) {
|
||||
|
||||
// Define data.
|
||||
$name = ! empty( $form_data['fields'][ $field_id ]['label'] ) ? $form_data['fields'][ $field_id ]['label'] : '';
|
||||
$amount = wpforms_sanitize_amount( $field_submit );
|
||||
|
||||
// Set final field details.
|
||||
wpforms()->get( 'process' )->fields[ $field_id ] = [
|
||||
'name' => sanitize_text_field( $name ),
|
||||
'value' => wpforms_format_amount( $amount, true ),
|
||||
'amount' => wpforms_format_amount( $amount ),
|
||||
'amount_raw' => $amount,
|
||||
'id' => absint( $field_id ),
|
||||
'type' => sanitize_key( $this->type ),
|
||||
];
|
||||
}
|
||||
}
|
89
wp-content/plugins/wpforms-lite/src/Forms/Honeypot.php
Normal file
89
wp-content/plugins/wpforms-lite/src/Forms/Honeypot.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace WPForms\Forms;
|
||||
|
||||
/**
|
||||
* Class Honeypot.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
class Honeypot {
|
||||
|
||||
/**
|
||||
* Initialise the actions for the Honeypot.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
public function init() {
|
||||
|
||||
$this->hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register hooks.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
public function hooks() {
|
||||
|
||||
add_action( 'wpforms_frontend_output', [ $this, 'render' ], 15, 5 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return function to render the honeypot.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*
|
||||
* @param array $form_data Form data and settings.
|
||||
*/
|
||||
public function render( $form_data ) {
|
||||
|
||||
if (
|
||||
empty( $form_data['settings']['honeypot'] ) ||
|
||||
'1' !== $form_data['settings']['honeypot']
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$names = [ 'Name', 'Phone', 'Comment', 'Message', 'Email', 'Website' ];
|
||||
|
||||
echo '<div class="wpforms-field wpforms-field-hp">';
|
||||
|
||||
echo '<label for="wpforms-' . $form_data['id'] . '-field-hp" class="wpforms-field-label">' . $names[ array_rand( $names ) ] . '</label>'; // phpcs:ignore
|
||||
|
||||
echo '<input type="text" name="wpforms[hp]" id="wpforms-' . $form_data['id'] . '-field-hp" class="wpforms-field-medium">'; // phpcs:ignore
|
||||
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate honeypot.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*
|
||||
* @param array $form_data Form data.
|
||||
* @param array $fields Fields.
|
||||
* @param array $entry Form entry.
|
||||
*
|
||||
* @return bool|string False or an string with the error.
|
||||
*/
|
||||
public function validate( array $form_data, array $fields, array $entry ) {
|
||||
|
||||
$honeypot = false;
|
||||
|
||||
if (
|
||||
! empty( $form_data['settings']['honeypot'] ) &&
|
||||
'1' === $form_data['settings']['honeypot'] &&
|
||||
! empty( $entry['hp'] )
|
||||
) {
|
||||
$honeypot = esc_html__( 'WPForms honeypot field triggered.', 'wpforms-lite' );
|
||||
}
|
||||
|
||||
// If we get passed an empty fields array, but we have the data in our form data, use it.
|
||||
if ( empty( $fields ) && isset( $form_data['fields'] ) ) {
|
||||
$fields = $form_data['fields'];
|
||||
}
|
||||
|
||||
return apply_filters( 'wpforms_process_honeypot', $honeypot, $fields, $entry, $form_data );
|
||||
}
|
||||
}
|
603
wp-content/plugins/wpforms-lite/src/Forms/IconChoices.php
Normal file
603
wp-content/plugins/wpforms-lite/src/Forms/IconChoices.php
Normal file
@@ -0,0 +1,603 @@
|
||||
<?php
|
||||
|
||||
namespace WPForms\Forms;
|
||||
|
||||
use WPForms\Helpers\PluginSilentUpgrader;
|
||||
use WPForms_Builder;
|
||||
use WPForms_Install_Skin;
|
||||
|
||||
/**
|
||||
* Icon Choices functionality.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*/
|
||||
class IconChoices {
|
||||
|
||||
/**
|
||||
* Remote URL to download the icon library from.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const FONT_AWESOME_URL = 'https://wpforms.com/wp-content/icon-choices.zip';
|
||||
|
||||
/**
|
||||
* Font Awesome version.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const FONT_AWESOME_VERSION = '6.4.0';
|
||||
|
||||
/**
|
||||
* Default icon.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const DEFAULT_ICON = 'face-smile';
|
||||
|
||||
/**
|
||||
* Default icon style.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const DEFAULT_ICON_STYLE = 'regular';
|
||||
|
||||
/**
|
||||
* Default accent color.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const DEFAULT_COLOR = [
|
||||
'classic' => '#0399ed',
|
||||
'modern' => '#066aab',
|
||||
];
|
||||
|
||||
/**
|
||||
* How many icons to display initially and paginate in the Icon Picker.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const DEFAULT_ICONS_PER_PAGE = 50;
|
||||
|
||||
/**
|
||||
* Absolute path to the cache directory.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $cache_base_path;
|
||||
|
||||
/**
|
||||
* Cache directory URL.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $cache_base_url;
|
||||
|
||||
/**
|
||||
* Absolute path to the icons data file.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $icons_data_file;
|
||||
|
||||
/**
|
||||
* Whether icon library is already installed.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $is_installed;
|
||||
|
||||
/**
|
||||
* Default list of icon sizes.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $default_icon_sizes;
|
||||
|
||||
/**
|
||||
* Initialize class.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*/
|
||||
public function init() {
|
||||
|
||||
$upload_dir = wpforms_upload_dir();
|
||||
|
||||
$this->cache_base_url = $upload_dir['url'] . '/icon-choices';
|
||||
$this->cache_base_path = $upload_dir['path'] . '/icon-choices';
|
||||
$this->icons_data_file = $this->cache_base_path . '/icons.json';
|
||||
|
||||
$this->default_icon_sizes = [
|
||||
'large' => [
|
||||
'label' => __( 'Large', 'wpforms-lite' ),
|
||||
'size' => 64,
|
||||
],
|
||||
'medium' => [
|
||||
'label' => __( 'Medium', 'wpforms-lite' ),
|
||||
'size' => 48,
|
||||
],
|
||||
'small' => [
|
||||
'label' => __( 'Small', 'wpforms-lite' ),
|
||||
'size' => 32,
|
||||
],
|
||||
];
|
||||
|
||||
$this->hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook into WordPress lifecycle.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*/
|
||||
private function hooks() {
|
||||
|
||||
// Add inline CSS with custom properties on the frontend.
|
||||
add_action( 'wpforms_frontend_css', [ $this, 'css_custom_properties' ] );
|
||||
|
||||
// Add inline CSS with custom properties in the form builder.
|
||||
if ( wpforms_is_admin_page( 'builder' ) ) {
|
||||
add_action( 'admin_head', [ $this, 'css_custom_properties' ] );
|
||||
}
|
||||
|
||||
// Load Font Awesome assets.
|
||||
add_action( 'wpforms_builder_enqueues', [ $this, 'enqueues' ] );
|
||||
|
||||
// Send data to the frontend.
|
||||
add_filter( 'wpforms_builder_strings', [ $this, 'get_strings' ], 10, 2 );
|
||||
|
||||
// Download and extract Font Awesome package.
|
||||
add_action( 'wp_ajax_wpforms_icon_choices_install', [ $this, 'install' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Font Awesome library data file.
|
||||
*
|
||||
* @since 1.8.3
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_icons_data_file() {
|
||||
|
||||
return $this->icons_data_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether Font Awesome library is already installed or not.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_installed() {
|
||||
|
||||
if ( $this->is_installed !== null ) {
|
||||
return $this->is_installed;
|
||||
}
|
||||
|
||||
$this->is_installed = file_exists( $this->icons_data_file );
|
||||
|
||||
return $this->is_installed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether Icon Choices mode is active on any of the fields in current form.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_active() {
|
||||
|
||||
$form_data = WPForms_Builder::instance()->form_data;
|
||||
|
||||
return wpforms_has_field_setting( 'choices_icons', $form_data, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Install Font Awesome library via Ajax.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*/
|
||||
public function install() {
|
||||
|
||||
check_ajax_referer( 'wpforms-builder', 'nonce' );
|
||||
|
||||
$this->run_install( $this->cache_base_path );
|
||||
$this->is_installed = true;
|
||||
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run Install Font Awesome library from our server.
|
||||
*
|
||||
* @since 1.8.3
|
||||
*
|
||||
* @param string $destination Destination path.
|
||||
*/
|
||||
public function run_install( $destination ) { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
|
||||
|
||||
// WordPress assumes it's a plugin/theme and tries to get translations. We don't need that, and it breaks JS output.
|
||||
remove_action( 'upgrader_process_complete', [ 'Language_Pack_Upgrader', 'async_upgrade' ], 20 );
|
||||
|
||||
if ( ! function_exists( 'request_filesystem_credentials' ) ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/file.php';
|
||||
}
|
||||
|
||||
require_once WPFORMS_PLUGIN_DIR . 'includes/admin/class-install-skin.php';
|
||||
|
||||
// Create the Upgrader with our custom skin that reports errors as WP JSON.
|
||||
$installer = new PluginSilentUpgrader( new WPForms_Install_Skin() );
|
||||
|
||||
// The installer skin reports any errors via wp_send_json_error() with generic error messages.
|
||||
$installer->init();
|
||||
$installer->run(
|
||||
[
|
||||
'package' => self::FONT_AWESOME_URL,
|
||||
'destination' => $destination,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all necessary Font Awesome assets.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @param string $view Current Form Builder view (panel).
|
||||
*/
|
||||
public function enqueues( $view ) {
|
||||
|
||||
if ( ! $this->is_installed() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_enqueue_style(
|
||||
'wpforms-icon-choices-font-awesome',
|
||||
$this->cache_base_url . '/css/fontawesome.min.css',
|
||||
[],
|
||||
self::FONT_AWESOME_VERSION
|
||||
);
|
||||
|
||||
wp_enqueue_style(
|
||||
'wpforms-icon-choices-font-awesome-brands',
|
||||
$this->cache_base_url . '/css/brands.min.css',
|
||||
[],
|
||||
self::FONT_AWESOME_VERSION
|
||||
);
|
||||
|
||||
wp_enqueue_style(
|
||||
'wpforms-icon-choices-font-awesome-regular',
|
||||
$this->cache_base_url . '/css/regular.min.css',
|
||||
[],
|
||||
self::FONT_AWESOME_VERSION
|
||||
);
|
||||
|
||||
wp_enqueue_style(
|
||||
'wpforms-icon-choices-font-awesome-solid',
|
||||
$this->cache_base_url . '/css/solid.min.css',
|
||||
[],
|
||||
self::FONT_AWESOME_VERSION
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define additional field properties specific to Icon Choices feature.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @see WPForms_Field_Checkbox::field_properties()
|
||||
* @see WPForms_Field_Radio::field_properties()
|
||||
* @see WPForms_Field_Payment_Checkbox::field_properties()
|
||||
* @see WPForms_Field_Payment_Multiple::field_properties()
|
||||
*
|
||||
* @param array $properties Field properties.
|
||||
* @param array $field Field settings.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function field_properties( $properties, $field ) {
|
||||
|
||||
$properties['input_container']['class'][] = 'wpforms-icon-choices';
|
||||
$properties['input_container']['class'][] = sanitize_html_class( 'wpforms-icon-choices-' . $field['choices_icons_style'] );
|
||||
$properties['input_container']['class'][] = sanitize_html_class( 'wpforms-icon-choices-' . $field['choices_icons_size'] );
|
||||
|
||||
$icon_color = isset( $field['choices_icons_color'] ) ? wpforms_sanitize_hex_color( $field['choices_icons_color'] ) : '';
|
||||
$icon_color = empty( $icon_color ) ? self::get_default_color() : $icon_color;
|
||||
|
||||
$properties['input_container']['attr']['style'] = "--wpforms-icon-choices-color: {$icon_color};";
|
||||
|
||||
foreach ( $properties['inputs'] as $key => $inputs ) {
|
||||
$properties['inputs'][ $key ]['container']['class'][] = 'wpforms-icon-choices-item';
|
||||
|
||||
if ( in_array( $field['choices_icons_style'], [ 'default', 'modern', 'classic' ], true ) ) {
|
||||
$properties['inputs'][ $key ]['class'][] = 'wpforms-screen-reader-element';
|
||||
}
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a single choice on the form front-end.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @see WPForms_Field_Checkbox::field_display()
|
||||
* @see WPForms_Field_Radio::field_display()
|
||||
* @see WPForms_Field_Payment_Checkbox::field_display()
|
||||
* @see WPForms_Field_Payment_Multiple::field_display()
|
||||
*
|
||||
* @param array $field Field settings.
|
||||
* @param array $choice Single choice item settings.
|
||||
* @param string $type Field input type.
|
||||
* @param string|null $label Custom label, used by Payment fields.
|
||||
*/
|
||||
public function field_display( $field, $choice, $type, $label = null ) {
|
||||
|
||||
// Only Payment fields supply a custom label.
|
||||
if ( ! $label ) {
|
||||
$label = $choice['label']['text'];
|
||||
}
|
||||
|
||||
printf(
|
||||
'<label %1$s>
|
||||
<span class="wpforms-icon-choices-icon">
|
||||
%2$s
|
||||
<span class="wpforms-icon-choices-icon-bg"></span>
|
||||
</span>
|
||||
<input type="%3$s" %4$s %5$s %6$s>
|
||||
<span class="wpforms-icon-choices-label">%7$s</span>
|
||||
</label>',
|
||||
wpforms_html_attributes( $choice['label']['id'], $choice['label']['class'], $choice['label']['data'], $choice['label']['attr'] ),
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
$this->get_icon( $choice['icon'], $choice['icon_style'], $field['choices_icons_size'] ),
|
||||
esc_attr( $type ),
|
||||
wpforms_html_attributes( $choice['id'], $choice['class'], $choice['data'], $choice['attr'] ),
|
||||
esc_attr( $choice['required'] ),
|
||||
checked( '1', $choice['default'], false ),
|
||||
wp_kses_post( $label )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output inline CSS custom properties (vars).
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @param null|array $forms Frontend forms, if available.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function css_custom_properties( $forms = null ) {
|
||||
|
||||
$hook = current_action();
|
||||
|
||||
// On the frontend, we need these properties only if Icon Choices is in use.
|
||||
if ( $hook === 'wpforms_frontend_css' && ! wpforms_has_field_setting( 'choices_icons', $forms, true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$selectors = [
|
||||
'wpforms_frontend_css' => '.wpforms-container',
|
||||
'admin_head' => '#wpforms-builder, .wpforms-icon-picker-container',
|
||||
];
|
||||
|
||||
/**
|
||||
* Add CSS custom properties.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @param array $properties CSS custom properties using CSS syntax.
|
||||
*/
|
||||
$custom_properties = (array) apply_filters( 'wpforms_forms_icon_choices_css_custom_properties', [] );
|
||||
|
||||
$icon_sizes = $this->get_icon_sizes();
|
||||
|
||||
foreach ( $icon_sizes as $slug => $data ) {
|
||||
$custom_properties[ "wpforms-icon-choices-size-{$slug}" ] = $data['size'] . 'px';
|
||||
}
|
||||
|
||||
$custom_properties_css = '';
|
||||
|
||||
foreach ( $custom_properties as $property => $value ) {
|
||||
$custom_properties_css .= "--{$property}: {$value};";
|
||||
}
|
||||
|
||||
printf(
|
||||
'<style id="wpforms-icon-choices-custom-properties">%s { %s }</style>',
|
||||
esc_attr( $selectors[ $hook ] ),
|
||||
esc_html( $custom_properties_css )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available icon sizes.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @return array A list of all icon sizes.
|
||||
*/
|
||||
public function get_icon_sizes() {
|
||||
|
||||
/**
|
||||
* Allow modifying the icon sizes.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @param array $icon_sizes {
|
||||
* Default icon sizes.
|
||||
*
|
||||
* @type string $key The icon slug.
|
||||
* @type array $value {
|
||||
* Individual icon size data.
|
||||
*
|
||||
* @type string $label Translatable label.
|
||||
* @type int $size The size value.
|
||||
* }
|
||||
* }
|
||||
* @param array $default_icon_sizes Default icon sizes for reference.
|
||||
*/
|
||||
$sizes = (array) apply_filters( 'wpforms_forms_icon_choices_get_icon_sizes', [], $this->default_icon_sizes );
|
||||
|
||||
return array_merge( $this->default_icon_sizes, $sizes );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read icons metadata from disk.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @param array $strings Strings and values sent to the frontend.
|
||||
* @param array $form Current form.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_strings( $strings, $form ) {
|
||||
|
||||
$strings['continue'] = esc_html__( 'Continue', 'wpforms-lite' );
|
||||
$strings['done'] = esc_html__( 'Done!', 'wpforms-lite' );
|
||||
$strings['uh_oh'] = esc_html__( 'Uh oh!', 'wpforms-lite' );
|
||||
|
||||
$strings['icon_choices'] = [
|
||||
'is_installed' => false,
|
||||
'is_active' => $this->is_active(),
|
||||
'default_icon' => self::DEFAULT_ICON,
|
||||
'default_icon_style' => self::DEFAULT_ICON_STYLE,
|
||||
'default_color' => self::get_default_color(),
|
||||
'icons' => [],
|
||||
'icons_per_page' => self::DEFAULT_ICONS_PER_PAGE,
|
||||
'strings' => [
|
||||
'install_prompt_content' => esc_html__( 'In order to use the Icon Choices feature, an icon library must be downloaded and installed. It\'s quick and easy, and you\'ll only have to do this once.', 'wpforms-lite' ),
|
||||
'install_title' => esc_html__( 'Installing Icon Library', 'wpforms-lite' ),
|
||||
'install_content' => esc_html__( 'This should only take a minute. Please don’t close or reload your browser window.', 'wpforms-lite' ),
|
||||
'install_success_content' => esc_html__( 'The icon library has been installed successfully. We will now save your form and reload the form builder.', 'wpforms-lite' ),
|
||||
'install_error_content' => wp_kses(
|
||||
sprintf( /* translators: %s - WPForms Support URL. */
|
||||
__( 'There was an error installing the icon library. Please try again later or <a href="%s" target="_blank" rel="noreferrer noopener">contact support</a> if the issue persists.', 'wpforms-lite' ),
|
||||
esc_url(
|
||||
wpforms_utm_link(
|
||||
'https://wpforms.com/account/support/',
|
||||
'builder-modal',
|
||||
'Icon Library Install Failure'
|
||||
)
|
||||
)
|
||||
),
|
||||
[
|
||||
'a' => [
|
||||
'href' => true,
|
||||
'target' => true,
|
||||
'rel' => true,
|
||||
],
|
||||
]
|
||||
),
|
||||
'reinstall_prompt_content' => esc_html__( 'The icon library appears to be missing or damaged. It will now be reinstalled.', 'wpforms-lite' ),
|
||||
'icon_picker_title' => esc_html__( 'Icon Picker', 'wpforms-lite' ),
|
||||
'icon_picker_description' => esc_html__( 'Browse or search for the perfect icon.', 'wpforms-lite' ),
|
||||
'icon_picker_search_placeholder' => esc_html__( 'Search 2000+ icons...', 'wpforms-lite' ),
|
||||
'icon_picker_not_found' => esc_html__( 'Sorry, we didn\'t find any matching icons.', 'wpforms-lite' ),
|
||||
],
|
||||
];
|
||||
|
||||
if ( ! $this->is_installed() ) {
|
||||
return $strings;
|
||||
}
|
||||
|
||||
$strings['icon_choices']['is_installed'] = true;
|
||||
$strings['icon_choices']['icons'] = $this->get_icons();
|
||||
|
||||
return $strings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an SVG icon code from a file for inline output in HTML.
|
||||
*
|
||||
* Note: the output does not need escaping.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @param string $icon Font Awesome icon name.
|
||||
* @param string $style Font Awesome style (solid, brands).
|
||||
* @param int $size Icon display size.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_icon( $icon, $style, $size ) {
|
||||
|
||||
$icon_sizes = $this->get_icon_sizes();
|
||||
$filename = realpath( "{$this->cache_base_path}/svgs/{$style}/{$icon}.svg" );
|
||||
|
||||
if ( ! $filename || ! is_file( $filename ) || ! is_readable( $filename ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$svg = file_get_contents( $filename );
|
||||
|
||||
if ( ! $svg ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$height = ! empty( $icon_sizes[ $size ]['size'] ) ? $icon_sizes[ $size ]['size'] : $icon_sizes['large']['size'];
|
||||
$width = $height * 1.25; // Icon width is equal or 25% larger/smaller than height. We force the largest value for all icons.
|
||||
|
||||
return str_replace( 'viewBox=', 'width="' . $width . '" height="' . $height . 'px" viewBox=', $svg );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available icons from the metadata file.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_icons() {
|
||||
|
||||
if ( ! is_file( $this->icons_data_file ) || ! is_readable( $this->icons_data_file ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$icons = file_get_contents( $this->icons_data_file );
|
||||
|
||||
if ( ! $icons ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return (array) json_decode( $icons, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default accent color.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_default_color() {
|
||||
|
||||
$render_engine = wpforms_get_render_engine();
|
||||
|
||||
return array_key_exists( $render_engine, self::DEFAULT_COLOR ) ? self::DEFAULT_COLOR[ $render_engine ] : self::DEFAULT_COLOR['modern'];
|
||||
}
|
||||
}
|
1245
wp-content/plugins/wpforms-lite/src/Forms/Locator.php
Normal file
1245
wp-content/plugins/wpforms-lite/src/Forms/Locator.php
Normal file
File diff suppressed because it is too large
Load Diff
307
wp-content/plugins/wpforms-lite/src/Forms/Preview.php
Normal file
307
wp-content/plugins/wpforms-lite/src/Forms/Preview.php
Normal file
@@ -0,0 +1,307 @@
|
||||
<?php
|
||||
|
||||
namespace WPForms\Forms;
|
||||
|
||||
/**
|
||||
* Form preview.
|
||||
*
|
||||
* @since 1.5.1
|
||||
*/
|
||||
class Preview {
|
||||
|
||||
/**
|
||||
* Form data.
|
||||
*
|
||||
* @since 1.5.1
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $form_data;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 1.5.1
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
if ( ! $this->is_preview_page() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current page request meets requirements for form preview page.
|
||||
*
|
||||
* @since 1.5.1
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_preview_page() {
|
||||
|
||||
// Only proceed for the form preview page.
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
if ( empty( $_GET['wpforms_form_preview'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for logged-in user with correct capabilities.
|
||||
if ( ! is_user_logged_in() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
$form_id = absint( $_GET['wpforms_form_preview'] );
|
||||
|
||||
if ( ! wpforms_current_user_can( 'view_form_single', $form_id ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fetch form details.
|
||||
$this->form_data = wpforms()->get( 'form' )->get( $form_id, [ 'content_only' => true ] );
|
||||
|
||||
// Check valid form was found.
|
||||
if ( empty( $this->form_data ) || empty( $this->form_data['id'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks.
|
||||
*
|
||||
* @since 1.5.1
|
||||
*/
|
||||
public function hooks() {
|
||||
|
||||
add_filter( 'wpforms_frontend_assets_header_force_load', '__return_true' );
|
||||
add_action( 'pre_get_posts', [ $this, 'pre_get_posts' ] );
|
||||
add_filter( 'the_title', [ $this, 'the_title' ], 100, 1 );
|
||||
add_filter( 'the_content', [ $this, 'the_content' ], 999 );
|
||||
add_filter( 'get_the_excerpt', [ $this, 'the_content' ], 999 );
|
||||
add_filter( 'home_template_hierarchy', [ $this, 'force_page_template_hierarchy' ] );
|
||||
add_filter( 'frontpage_template_hierarchy', [ $this, 'force_page_template_hierarchy' ] );
|
||||
add_filter( 'wpforms_smarttags_process_page_title_value', [ $this, 'smart_tags_process_page_title_value' ], 10, 5 );
|
||||
add_filter( 'post_thumbnail_html', '__return_empty_string' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify query, limit to one post.
|
||||
*
|
||||
* @since 1.5.1
|
||||
* @since 1.7.0 Added `page_id`, `post_type` and `post__in` query variables.
|
||||
*
|
||||
* @param \WP_Query $query The WP_Query instance.
|
||||
*/
|
||||
public function pre_get_posts( $query ) {
|
||||
|
||||
if ( is_admin() || ! $query->is_main_query() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$query->set( 'page_id', '' );
|
||||
$query->set( 'post_type', 'wpforms' );
|
||||
$query->set( 'post__in', empty( $this->form_data['id'] ) ? [] : [ (int) $this->form_data['id'] ] );
|
||||
$query->set( 'posts_per_page', 1 );
|
||||
|
||||
// The preview page reads as the home page and as an non-singular posts page, neither of which are actually the case.
|
||||
// So we hardcode the correct values for those properties in the query.
|
||||
$query->is_home = false;
|
||||
$query->is_singular = true;
|
||||
$query->is_single = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize form preview page title.
|
||||
*
|
||||
* @since 1.5.1
|
||||
*
|
||||
* @param string $title Page title.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function the_title( $title ) {
|
||||
|
||||
if ( in_the_loop() ) {
|
||||
$title = sprintf( /* translators: %s - form name. */
|
||||
esc_html__( '%s Preview', 'wpforms-lite' ),
|
||||
! empty( $this->form_data['settings']['form_title'] ) ? sanitize_text_field( $this->form_data['settings']['form_title'] ) : esc_html__( 'Form', 'wpforms-lite' )
|
||||
);
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize form preview page content.
|
||||
*
|
||||
* @since 1.5.1
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function the_content() {
|
||||
|
||||
if ( ! isset( $this->form_data['id'] ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( ! wpforms_current_user_can( 'view_form_single', $this->form_data['id'] ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$admin_url = admin_url( 'admin.php' );
|
||||
|
||||
$links = [];
|
||||
|
||||
if ( wpforms_current_user_can( 'edit_form_single', $this->form_data['id'] ) ) {
|
||||
$links[] = [
|
||||
'url' => esc_url(
|
||||
add_query_arg(
|
||||
[
|
||||
'page' => 'wpforms-builder',
|
||||
'view' => 'fields',
|
||||
'form_id' => absint( $this->form_data['id'] ),
|
||||
],
|
||||
$admin_url
|
||||
)
|
||||
),
|
||||
'text' => esc_html__( 'Edit Form', 'wpforms-lite' ),
|
||||
];
|
||||
}
|
||||
|
||||
if ( wpforms()->is_pro() && wpforms_current_user_can( 'view_entries_form_single', $this->form_data['id'] ) ) {
|
||||
$links[] = [
|
||||
'url' => esc_url(
|
||||
add_query_arg(
|
||||
[
|
||||
'page' => 'wpforms-entries',
|
||||
'view' => 'list',
|
||||
'form_id' => absint( $this->form_data['id'] ),
|
||||
],
|
||||
$admin_url
|
||||
)
|
||||
),
|
||||
'text' => esc_html__( 'View Entries', 'wpforms-lite' ),
|
||||
];
|
||||
}
|
||||
|
||||
if (
|
||||
wpforms_current_user_can( wpforms_get_capability_manage_options(), $this->form_data['id'] ) &&
|
||||
wpforms()->get( 'payment' )->get_by( 'form_id', $this->form_data['id'] )
|
||||
) {
|
||||
$links[] = [
|
||||
'url' => esc_url(
|
||||
add_query_arg(
|
||||
[
|
||||
'page' => 'wpforms-payments',
|
||||
'form_id' => absint( $this->form_data['id'] ),
|
||||
],
|
||||
$admin_url
|
||||
)
|
||||
),
|
||||
'text' => esc_html__( 'View Payments', 'wpforms-lite' ),
|
||||
];
|
||||
}
|
||||
|
||||
if ( ! empty( $_GET['new_window'] ) ) { // phpcs:ignore
|
||||
$links[] = [
|
||||
'url' => 'javascript:window.close();',
|
||||
'text' => esc_html__( 'Close this window', 'wpforms-lite' ),
|
||||
];
|
||||
}
|
||||
|
||||
$content = '<p>';
|
||||
$content .= esc_html__( 'This is a preview of the latest saved revision of your form. If this preview does not match your form, save your changes and then refresh this page. This form preview is not publicly accessible.', 'wpforms-lite' );
|
||||
|
||||
if ( ! empty( $links ) ) {
|
||||
$content .= '<br>';
|
||||
$content .= '<span class="wpforms-preview-notice-links">';
|
||||
|
||||
foreach ( $links as $key => $link ) {
|
||||
$content .= '<a href="' . $link['url'] . '">' . $link['text'] . '</a>';
|
||||
$l = array_keys( $links );
|
||||
|
||||
if ( end( $l ) !== $key ) {
|
||||
$content .= ' <span style="display:inline-block;margin:0 6px;opacity: 0.5">|</span> ';
|
||||
}
|
||||
}
|
||||
|
||||
$content .= '</span>';
|
||||
}
|
||||
$content .= '</p>';
|
||||
|
||||
$content .= '<p>';
|
||||
$content .= sprintf(
|
||||
wp_kses(
|
||||
/* translators: %s - WPForms doc link. */
|
||||
__( 'For form testing tips, check out our <a href="%s" target="_blank" rel="noopener noreferrer">complete guide!</a>', 'wpforms-lite' ),
|
||||
[
|
||||
'a' => [
|
||||
'href' => [],
|
||||
'target' => [],
|
||||
'rel' => [],
|
||||
],
|
||||
]
|
||||
),
|
||||
esc_url( wpforms_utm_link( 'https://wpforms.com/docs/how-to-properly-test-your-wordpress-forms-before-launching-checklist/', 'Form Preview', 'Form Testing Tips Documentation' ) )
|
||||
);
|
||||
$content .= '</p>';
|
||||
|
||||
$content .= do_shortcode( '[wpforms id="' . absint( $this->form_data['id'] ) . '"]' );
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force page template types.
|
||||
*
|
||||
* @since 1.7.2
|
||||
*
|
||||
* @param array $templates A list of template candidates, in descending order of priority.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function force_page_template_hierarchy( $templates ) {
|
||||
|
||||
return [ 'page.php', 'single.php', 'index.php' ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust value of the {page_title} smart tag.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @param string $content Content.
|
||||
* @param array $form_data Form data.
|
||||
* @param array $fields List of fields.
|
||||
* @param string $entry_id Entry ID.
|
||||
* @param object $smart_tag_object The smart tag object or the Generic object for those cases when class unregistered.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function smart_tags_process_page_title_value( $content, $form_data, $fields, $entry_id, $smart_tag_object ) {
|
||||
|
||||
return sprintf( /* translators: %s - form name. */
|
||||
esc_html__( '%s Preview', 'wpforms-lite' ),
|
||||
! empty( $form_data['settings']['form_title'] ) ? sanitize_text_field( $form_data['settings']['form_title'] ) : esc_html__( 'Form', 'wpforms-lite' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force page template types.
|
||||
*
|
||||
* @since 1.5.1
|
||||
* @deprecated 1.7.2
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function template_include() {
|
||||
|
||||
_deprecated_function( __METHOD__, '1.7.2 of the WPForms plugin' );
|
||||
|
||||
return locate_template( [ 'page.php', 'single.php', 'index.php' ] );
|
||||
}
|
||||
}
|
280
wp-content/plugins/wpforms-lite/src/Forms/Submission.php
Normal file
280
wp-content/plugins/wpforms-lite/src/Forms/Submission.php
Normal file
@@ -0,0 +1,280 @@
|
||||
<?php
|
||||
|
||||
namespace WPForms\Forms;
|
||||
|
||||
/**
|
||||
* Class Submission.
|
||||
*
|
||||
* @since 1.7.4
|
||||
*/
|
||||
class Submission {
|
||||
|
||||
/**
|
||||
* The form fields.
|
||||
*
|
||||
* @since 1.7.4
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fields;
|
||||
|
||||
/**
|
||||
* The form entry.
|
||||
*
|
||||
* @since 1.7.4
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $entry;
|
||||
|
||||
/**
|
||||
* The form ID.
|
||||
*
|
||||
* @since 1.7.4
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $form_id;
|
||||
|
||||
/**
|
||||
* The form data.
|
||||
*
|
||||
* @since 1.7.4
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $form_data;
|
||||
|
||||
/**
|
||||
* The date.
|
||||
*
|
||||
* @since 1.7.4
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $date;
|
||||
|
||||
/**
|
||||
* Register the submission data.
|
||||
*
|
||||
* @since 1.7.4
|
||||
* @since 1.8.2 Added a return of instance.
|
||||
*
|
||||
* @param array $fields The form fields.
|
||||
* @param array $entry The form entry.
|
||||
* @param int $form_id The form ID.
|
||||
* @param array $form_data The form data.
|
||||
*
|
||||
* @return Submission
|
||||
*/
|
||||
public function register( array $fields, array $entry, $form_id, array $form_data = [] ) {
|
||||
|
||||
$this->fields = $fields;
|
||||
$this->entry = $entry;
|
||||
$this->form_id = $form_id;
|
||||
$this->form_data = $form_data;
|
||||
$this->date = gmdate( 'Y-m-d H:i:s' );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the submission data.
|
||||
*
|
||||
* @since 1.7.4
|
||||
*
|
||||
* @return array|void
|
||||
*/
|
||||
public function prepare_entry_data() {
|
||||
|
||||
/**
|
||||
* Provide the opportunity to disable entry saving.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param bool $entry_save Entry save flag. Defaults to true.
|
||||
* @param array $fields Fields data.
|
||||
* @param array $entry Entry data.
|
||||
* @param array $form_data Form data.
|
||||
*/
|
||||
if ( ! apply_filters( 'wpforms_entry_save', true, $this->fields, $this->entry, $this->form_data ) ) { // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
|
||||
return;
|
||||
}
|
||||
|
||||
$submitted_fields = $this->get_fields();
|
||||
$user_info = $this->get_user_info( $submitted_fields );
|
||||
|
||||
/**
|
||||
* Information about the entry, that is ready to be saved into the main entries table,
|
||||
* which is used for displaying a list of entries and partially for search.
|
||||
*
|
||||
* @since 1.5.9
|
||||
*
|
||||
* @param array $entry_data Information about the entry, that will be saved into the DB.
|
||||
* @param array $form_data Form data.
|
||||
*/
|
||||
return (array) apply_filters( // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
|
||||
'wpforms_entry_save_args',
|
||||
[
|
||||
'form_id' => absint( $this->form_id ),
|
||||
'user_id' => absint( $user_info['user_id'] ),
|
||||
'fields' => wp_json_encode( $submitted_fields ),
|
||||
'ip_address' => sanitize_text_field( $user_info['user_ip'] ),
|
||||
'user_agent' => sanitize_text_field( $user_info['user_agent'] ),
|
||||
'date' => $this->date,
|
||||
'user_uuid' => sanitize_text_field( $user_info['user_uuid'] ),
|
||||
],
|
||||
$this->form_data
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the payment submission data.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function prepare_payment_data() {
|
||||
|
||||
$submitted_fields = $this->get_fields();
|
||||
$total_amount = wpforms_get_total_payment( $submitted_fields );
|
||||
|
||||
/**
|
||||
* Information about the payment, that is ready to be saved into the main payments table,
|
||||
* which is used for displaying a list of payments and partially for search.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $payment_data Information about the payment, that will be saved into the DB.
|
||||
* @param array $fields Final/sanitized submitted field data.
|
||||
* @param array $form_data Form data and settings.
|
||||
*/
|
||||
$payment_data = (array) apply_filters(
|
||||
'wpforms_forms_submission_prepare_payment_data',
|
||||
[
|
||||
'form_id' => absint( $this->form_id ),
|
||||
'subtotal_amount' => $total_amount,
|
||||
'total_amount' => $total_amount,
|
||||
'currency' => wpforms_get_currency(),
|
||||
'entry_id' => absint( $this->entry['entry_id'] ),
|
||||
'date_created_gmt' => $this->date,
|
||||
'date_updated_gmt' => $this->date,
|
||||
],
|
||||
$submitted_fields,
|
||||
$this->form_data
|
||||
);
|
||||
|
||||
if ( empty( $payment_data['type'] ) ) {
|
||||
$payment_data['type'] = ! empty( $payment_data['subscription_id'] ) ? 'subscription' : 'one-time';
|
||||
}
|
||||
|
||||
return $payment_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the payment meta data for each payment.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function prepare_payment_meta() {
|
||||
|
||||
$submitted_fields = $this->get_fields();
|
||||
$user_info = $this->get_user_info( $submitted_fields );
|
||||
|
||||
/**
|
||||
* Payment meta that is ready to be saved into the payments_meta table.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $payment_meta Payment meta that will be saved into the DB.
|
||||
* @param array $fields Final/sanitized submitted field data.
|
||||
* @param array $form_data Form data and settings.
|
||||
*/
|
||||
return (array) apply_filters(
|
||||
'wpforms_forms_submission_prepare_payment_meta',
|
||||
[
|
||||
'fields' => ! $this->entry['entry_id'] ? wp_json_encode( $submitted_fields ) : '',
|
||||
'user_id' => absint( $user_info['user_id'] ),
|
||||
'user_agent' => sanitize_text_field( $user_info['user_agent'] ),
|
||||
'user_uuid' => sanitize_text_field( $user_info['user_uuid'] ),
|
||||
'ip_address' => sanitize_text_field( $user_info['user_ip'] ),
|
||||
],
|
||||
$submitted_fields,
|
||||
$this->form_data
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get entry fields.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_fields() {
|
||||
|
||||
/**
|
||||
* Filter the entry data before saving.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param array $fields Fields data.
|
||||
* @param array $entry Entry data.
|
||||
* @param array $form_data Form data.
|
||||
*/
|
||||
return (array) apply_filters( 'wpforms_entry_save_data', $this->fields, $this->entry, $this->form_data ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user info.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param array $fields Fields data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_user_info( $fields ) {
|
||||
|
||||
$user_info = [
|
||||
'user_ip' => '',
|
||||
'user_agent' => '',
|
||||
'user_id' => is_user_logged_in() ? get_current_user_id() : 0,
|
||||
'user_uuid' => wpforms_is_collecting_cookies_allowed() && ! empty( $_COOKIE['_wpfuuid'] ) ? sanitize_key( $_COOKIE['_wpfuuid'] ) : '',
|
||||
];
|
||||
|
||||
/**
|
||||
* Allow developers disable saving user IP and User Agent within the entry.
|
||||
*
|
||||
* @since 1.5.1
|
||||
*
|
||||
* @param bool $disable True if you need to disable storing IP and UA within the entry. Defaults to false.
|
||||
* @param array $fields Fields data.
|
||||
* @param array $form_data Form data.
|
||||
*/
|
||||
// phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
|
||||
$is_ip_disabled = apply_filters( 'wpforms_disable_entry_user_ip', '__return_false', $fields, $this->form_data );
|
||||
|
||||
// If GDPR enhancements are enabled and user details are disabled
|
||||
// globally or in the form settings, discard the IP and UA.
|
||||
if (
|
||||
! $is_ip_disabled ||
|
||||
! wpforms_is_collecting_ip_allowed( $this->form_data )
|
||||
) {
|
||||
return $user_info;
|
||||
}
|
||||
|
||||
$user_info['user_ip'] = wpforms_get_ip();
|
||||
|
||||
if ( empty( $_SERVER['HTTP_USER_AGENT'] ) ) {
|
||||
return $user_info;
|
||||
}
|
||||
|
||||
$user_info['user_agent'] = substr( sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ), 0, 256 );
|
||||
|
||||
return $user_info;
|
||||
}
|
||||
}
|
288
wp-content/plugins/wpforms-lite/src/Forms/Token.php
Normal file
288
wp-content/plugins/wpforms-lite/src/Forms/Token.php
Normal file
@@ -0,0 +1,288 @@
|
||||
<?php
|
||||
|
||||
namespace WPForms\Forms;
|
||||
|
||||
/**
|
||||
* Class Token.
|
||||
*
|
||||
* This token class generates tokens that are used in our Anti-Spam checking mechanism.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
class Token {
|
||||
|
||||
/**
|
||||
* Initialise the actions for the Anti-spam.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
public function init() {
|
||||
|
||||
$this->hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register hooks.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
public function hooks() {
|
||||
|
||||
add_filter( 'wpforms_frontend_form_atts', [ $this, 'add_token_to_form_atts' ], 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a valid token.
|
||||
*
|
||||
* @since 1.6.2
|
||||
* @since 1.7.1 Added the $form_data argument.
|
||||
*
|
||||
* @param mixed $current True to use current time, otherwise a timestamp string.
|
||||
* @param array $form_data Form data and settings.
|
||||
*
|
||||
* @return string Token.
|
||||
*/
|
||||
public function get( $current = true, $form_data = [] ) {
|
||||
|
||||
// If $current was not passed, or it is true, we use the current timestamp.
|
||||
// If $current was passed in as a string, we'll use that passed in timestamp.
|
||||
if ( $current !== true ) {
|
||||
$time = $current;
|
||||
} else {
|
||||
$time = time();
|
||||
}
|
||||
|
||||
// Format the timestamp to be less exact, as we want to deal in days.
|
||||
// June 19th, 2020 would get formatted as: 1906202017125.
|
||||
// Day of the month, month number, year, day number of the year, week number of the year.
|
||||
$token_data = gmdate( 'dmYzW', $time );
|
||||
|
||||
if ( ! empty( $form_data['id'] ) ) {
|
||||
$token_data .= "::{$form_data['id']}";
|
||||
}
|
||||
|
||||
// Combine our token date and our token salt, and md5 it.
|
||||
return md5( $token_data . \WPForms\Helpers\Crypto::get_secret_key() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the array of valid tokens to check for. These include two days
|
||||
* before the current date to account for long cache times.
|
||||
*
|
||||
* These two filters are available if a user wants to extend the times.
|
||||
* 'wpforms_form_token_check_before_today'
|
||||
* 'wpforms_form_token_check_after_today'
|
||||
*
|
||||
* @since 1.6.2
|
||||
* @since 1.7.1 Added the $form_data argument.
|
||||
*
|
||||
* @param array $form_data Form data and settings.
|
||||
*
|
||||
* @return array Array of all valid tokens to check against.
|
||||
*/
|
||||
public function get_valid_tokens( $form_data = [] ) {
|
||||
|
||||
$current_date = time();
|
||||
|
||||
// Create our array of times to check before today. A user with a longer
|
||||
// cache time can extend this. A user with a shorter cache time can remove times.
|
||||
$valid_token_times_before = apply_filters(
|
||||
'wpforms_form_token_check_before_today',
|
||||
[
|
||||
( 2 * DAY_IN_SECONDS ), // Two days ago.
|
||||
( 1 * DAY_IN_SECONDS ), // One day ago.
|
||||
]
|
||||
);
|
||||
|
||||
// Mostly to catch edge cases like the form page loading and submitting on two different days.
|
||||
// This probably won't be filtered by users too much, but they could extend it.
|
||||
$valid_token_times_after = apply_filters(
|
||||
'wpforms_form_token_check_after_today',
|
||||
[
|
||||
( 45 * MINUTE_IN_SECONDS ), // Add in 45 minutes past today to catch some midnight edge cases.
|
||||
]
|
||||
);
|
||||
|
||||
// Built up our valid tokens.
|
||||
$valid_tokens = [];
|
||||
|
||||
// Add in all the previous times we check.
|
||||
foreach ( $valid_token_times_before as $time ) {
|
||||
$valid_tokens[] = $this->get( $current_date - $time, $form_data );
|
||||
}
|
||||
|
||||
// Add in our current date.
|
||||
$valid_tokens[] = $this->get( $current_date, $form_data );
|
||||
|
||||
// Add in the times after our check.
|
||||
foreach ( $valid_token_times_after as $time ) {
|
||||
$valid_tokens[] = $this->get( $current_date + $time, $form_data );
|
||||
}
|
||||
|
||||
return $valid_tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given token is valid or not.
|
||||
*
|
||||
* Tokens are valid for some period of time (see wpforms_token_validity_in_hours
|
||||
* and wpforms_token_validity_in_days to extend the validation period).
|
||||
* By default tokens are valid for day.
|
||||
*
|
||||
* @since 1.6.2
|
||||
* @since 1.7.1 Added the $form_data argument.
|
||||
*
|
||||
* @param string $token Token to validate.
|
||||
* @param array $form_data Form data and settings.
|
||||
*
|
||||
* @return bool Whether the token is valid or not.
|
||||
*/
|
||||
public function verify( $token, $form_data = [] ) {
|
||||
|
||||
// Check to see if our token is inside the valid tokens.
|
||||
return in_array( $token, $this->get_valid_tokens( $form_data ), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the token to the form attributes.
|
||||
*
|
||||
* @since 1.6.2
|
||||
* @since 1.7.1 Added the $form_data argument.
|
||||
*
|
||||
* @param array $attrs Form attributes.
|
||||
* @param array $form_data Form data and settings.
|
||||
*
|
||||
* @return array Form attributes.
|
||||
*/
|
||||
public function add_token_to_form_atts( array $attrs, array $form_data ) {
|
||||
|
||||
$attrs['atts']['data-token'] = $this->get( true, $form_data );
|
||||
|
||||
return $attrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Anti-spam if enabled.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*
|
||||
* @param array $form_data Form data.
|
||||
* @param array $fields Fields.
|
||||
* @param array $entry Form entry.
|
||||
*
|
||||
* @return bool|string True or a string with the error.
|
||||
*/
|
||||
public function validate( array $form_data, array $fields, array $entry ) {
|
||||
|
||||
// Bail out if we don't have the antispam setting.
|
||||
if ( empty( $form_data['settings']['antispam'] ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Bail out if the antispam setting isn't enabled.
|
||||
if ( $form_data['settings']['antispam'] !== '1' ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$valid = isset( $entry['token'] ) && $this->verify( $entry['token'], $form_data );
|
||||
$valid = $this->process_antispam_filter_wrapper( $valid, $fields, $entry, $form_data );
|
||||
|
||||
if ( ! $valid ) {
|
||||
return $this->get_missing_token_message();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to run our filter on all the responses for the antispam checks.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*
|
||||
* @param bool $is_valid_not_spam Is valid entry or not.
|
||||
* @param array $fields Form Fields.
|
||||
* @param array $entry Form entry.
|
||||
* @param array $form_data Form Data.
|
||||
*
|
||||
* @return bool Is valid or not.
|
||||
*/
|
||||
public function process_antispam_filter_wrapper( $is_valid_not_spam, array $fields, array $entry, array $form_data ) {
|
||||
|
||||
return apply_filters( 'wpforms_process_antispam', $is_valid_not_spam, $fields, $entry, $form_data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to get the missing token message.
|
||||
*
|
||||
* @since 1.6.2.1
|
||||
*
|
||||
* @return string missing token message.
|
||||
*/
|
||||
private function get_missing_token_message() {
|
||||
|
||||
return $this->get_error_message( esc_html__( 'This page isn\'t loading JavaScript properly, and the form will not be able to submit.', 'wpforms-lite' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to get the invalid token message.
|
||||
*
|
||||
* @since 1.6.2.1
|
||||
*
|
||||
* @return string Invalid token message.
|
||||
*/
|
||||
private function get_invalid_token_message() {
|
||||
|
||||
return $this->get_error_message( esc_html__( 'Form token is invalid. Please refresh the page.', 'wpforms-lite' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get error message depends on user.
|
||||
*
|
||||
* @since 1.6.4.1
|
||||
*
|
||||
* @param string $text Message text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_error_message( $text ) {
|
||||
|
||||
return wpforms_current_user_can() ? $text . $this->maybe_get_support_text() : $this->get_non_logged_user_error_message();
|
||||
}
|
||||
|
||||
/**
|
||||
* Non logged user error message.
|
||||
*
|
||||
* @since 1.6.4.1
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_non_logged_user_error_message() {
|
||||
|
||||
return esc_html__( 'The form was unable to submit. Please contact the site administrator.', 'wpforms-lite' );
|
||||
}
|
||||
|
||||
/**
|
||||
* If a user is a super admin, add a support link to the message.
|
||||
*
|
||||
* @since 1.6.2.1
|
||||
*
|
||||
* @return string Support text if super admin, empty string if not.
|
||||
*/
|
||||
private function maybe_get_support_text() {
|
||||
|
||||
// If user isn't a super admin, don't return any text.
|
||||
if ( ! is_super_admin() ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// If the user is an admin, return text with a link to support.
|
||||
// We add a space here to separate the sentences, but outside of the localized
|
||||
// text to avoid it being removed.
|
||||
return ' ' . sprintf(
|
||||
// translators: placeholders are links.
|
||||
esc_html__( 'Please check out our %1$stroubleshooting guide%2$s for details on resolving this issue.', 'wpforms-lite' ),
|
||||
'<a href="https://wpforms.com/docs/getting-support-wpforms/">',
|
||||
'</a>'
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user