?
class-wp-rest-post-meta-fields.php 0000666 00000002334 15123445157 0013151 0 ustar 00 <?php
/**
* REST API: WP_REST_Post_Meta_Fields class
*
* @package WordPress
* @subpackage REST_API
* @since 4.7.0
*/
/**
* Core class used to manage meta values for posts via the REST API.
*
* @since 4.7.0
*
* @see WP_REST_Meta_Fields
*/
class WP_REST_Post_Meta_Fields extends WP_REST_Meta_Fields {
/**
* Post type to register fields for.
*
* @since 4.7.0
* @var string
*/
protected $post_type;
/**
* Constructor.
*
* @since 4.7.0
*
* @param string $post_type Post type to register fields for.
*/
public function __construct( $post_type ) {
$this->post_type = $post_type;
}
/**
* Retrieves the post meta type.
*
* @since 4.7.0
*
* @return string The meta type.
*/
protected function get_meta_type() {
return 'post';
}
/**
* Retrieves the post meta subtype.
*
* @since 4.9.8
*
* @return string Subtype for the meta type, or empty string if no specific subtype.
*/
protected function get_meta_subtype() {
return $this->post_type;
}
/**
* Retrieves the type for register_rest_field().
*
* @since 4.7.0
*
* @see register_rest_field()
*
* @return string The REST field type.
*/
public function get_rest_field_type() {
return $this->post_type;
}
}
class-wp-rest-meta-fields.php 0000666 00000031605 15123445157 0012171 0 ustar 00 <?php
/**
* REST API: WP_REST_Meta_Fields class
*
* @package WordPress
* @subpackage REST_API
* @since 4.7.0
*/
/**
* Core class to manage meta values for an object via the REST API.
*
* @since 4.7.0
*/
abstract class WP_REST_Meta_Fields {
/**
* Retrieves the object meta type.
*
* @since 4.7.0
*
* @return string One of 'post', 'comment', 'term', 'user', or anything
* else supported by `_get_meta_table()`.
*/
abstract protected function get_meta_type();
/**
* Retrieves the object type for register_rest_field().
*
* @since 4.7.0
*
* @return string The REST field type, such as post type name, taxonomy name, 'comment', or `user`.
*/
abstract protected function get_rest_field_type();
/**
* Registers the meta field.
*
* @since 4.7.0
*
* @see register_rest_field()
*/
public function register_field() {
register_rest_field( $this->get_rest_field_type(), 'meta', array(
'get_callback' => array( $this, 'get_value' ),
'update_callback' => array( $this, 'update_value' ),
'schema' => $this->get_field_schema(),
));
}
/**
* Retrieves the meta field value.
*
* @since 4.7.0
*
* @param int $object_id Object ID to fetch meta for.
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|object Object containing the meta values by name, otherwise WP_Error object.
*/
public function get_value( $object_id, $request ) {
$fields = $this->get_registered_fields();
$response = array();
foreach ( $fields as $meta_key => $args ) {
$name = $args['name'];
$all_values = get_metadata( $this->get_meta_type(), $object_id, $meta_key, false );
if ( $args['single'] ) {
if ( empty( $all_values ) ) {
$value = $args['schema']['default'];
} else {
$value = $all_values[0];
}
$value = $this->prepare_value_for_response( $value, $request, $args );
} else {
$value = array();
foreach ( $all_values as $row ) {
$value[] = $this->prepare_value_for_response( $row, $request, $args );
}
}
$response[ $name ] = $value;
}
return $response;
}
/**
* Prepares a meta value for a response.
*
* This is required because some native types cannot be stored correctly
* in the database, such as booleans. We need to cast back to the relevant
* type before passing back to JSON.
*
* @since 4.7.0
*
* @param mixed $value Meta value to prepare.
* @param WP_REST_Request $request Current request object.
* @param array $args Options for the field.
* @return mixed Prepared value.
*/
protected function prepare_value_for_response( $value, $request, $args ) {
if ( ! empty( $args['prepare_callback'] ) ) {
$value = call_user_func( $args['prepare_callback'], $value, $request, $args );
}
return $value;
}
/**
* Updates meta values.
*
* @since 4.7.0
*
* @param array $meta Array of meta parsed from the request.
* @param int $object_id Object ID to fetch meta for.
* @return WP_Error|null WP_Error if one occurs, null on success.
*/
public function update_value( $meta, $object_id ) {
$fields = $this->get_registered_fields();
foreach ( $fields as $meta_key => $args ) {
$name = $args['name'];
if ( ! array_key_exists( $name, $meta ) ) {
continue;
}
/*
* A null value means reset the field, which is essentially deleting it
* from the database and then relying on the default value.
*/
if ( is_null( $meta[ $name ] ) ) {
$result = $this->delete_meta_value( $object_id, $meta_key, $name );
if ( is_wp_error( $result ) ) {
return $result;
}
continue;
}
$is_valid = rest_validate_value_from_schema( $meta[ $name ], $args['schema'], 'meta.' . $name );
if ( is_wp_error( $is_valid ) ) {
$is_valid->add_data( array( 'status' => 400 ) );
return $is_valid;
}
$value = rest_sanitize_value_from_schema( $meta[ $name ], $args['schema'] );
if ( $args['single'] ) {
$result = $this->update_meta_value( $object_id, $meta_key, $name, $value );
} else {
$result = $this->update_multi_meta_value( $object_id, $meta_key, $name, $value );
}
if ( is_wp_error( $result ) ) {
return $result;
}
}
return null;
}
/**
* Deletes a meta value for an object.
*
* @since 4.7.0
*
* @param int $object_id Object ID the field belongs to.
* @param string $meta_key Key for the field.
* @param string $name Name for the field that is exposed in the REST API.
* @return bool|WP_Error True if meta field is deleted, WP_Error otherwise.
*/
protected function delete_meta_value( $object_id, $meta_key, $name ) {
$meta_type = $this->get_meta_type();
if ( ! current_user_can( "delete_{$meta_type}_meta", $object_id, $meta_key ) ) {
return new WP_Error(
'rest_cannot_delete',
/* translators: %s: custom field key */
sprintf( __( 'Sorry, you are not allowed to edit the %s custom field.' ), $name ),
array( 'key' => $name, 'status' => rest_authorization_required_code() )
);
}
if ( ! delete_metadata( $meta_type, $object_id, wp_slash( $meta_key ) ) ) {
return new WP_Error(
'rest_meta_database_error',
__( 'Could not delete meta value from database.' ),
array( 'key' => $name, 'status' => WP_Http::INTERNAL_SERVER_ERROR )
);
}
return true;
}
/**
* Updates multiple meta values for an object.
*
* Alters the list of values in the database to match the list of provided values.
*
* @since 4.7.0
*
* @param int $object_id Object ID to update.
* @param string $meta_key Key for the custom field.
* @param string $name Name for the field that is exposed in the REST API.
* @param array $values List of values to update to.
* @return bool|WP_Error True if meta fields are updated, WP_Error otherwise.
*/
protected function update_multi_meta_value( $object_id, $meta_key, $name, $values ) {
$meta_type = $this->get_meta_type();
if ( ! current_user_can( "edit_{$meta_type}_meta", $object_id, $meta_key ) ) {
return new WP_Error(
'rest_cannot_update',
/* translators: %s: custom field key */
sprintf( __( 'Sorry, you are not allowed to edit the %s custom field.' ), $name ),
array( 'key' => $name, 'status' => rest_authorization_required_code() )
);
}
$current = get_metadata( $meta_type, $object_id, $meta_key, false );
$to_remove = $current;
$to_add = $values;
foreach ( $to_add as $add_key => $value ) {
$remove_keys = array_keys( $to_remove, $value, true );
if ( empty( $remove_keys ) ) {
continue;
}
if ( count( $remove_keys ) > 1 ) {
// To remove, we need to remove first, then add, so don't touch.
continue;
}
$remove_key = $remove_keys[0];
unset( $to_remove[ $remove_key ] );
unset( $to_add[ $add_key ] );
}
// `delete_metadata` removes _all_ instances of the value, so only call once.
$to_remove = array_unique( $to_remove );
foreach ( $to_remove as $value ) {
if ( ! delete_metadata( $meta_type, $object_id, wp_slash( $meta_key ), wp_slash( $value ) ) ) {
return new WP_Error(
'rest_meta_database_error',
__( 'Could not update meta value in database.' ),
array( 'key' => $name, 'status' => WP_Http::INTERNAL_SERVER_ERROR )
);
}
}
foreach ( $to_add as $value ) {
if ( ! add_metadata( $meta_type, $object_id, wp_slash( $meta_key ), wp_slash( $value ) ) ) {
return new WP_Error(
'rest_meta_database_error',
__( 'Could not update meta value in database.' ),
array( 'key' => $name, 'status' => WP_Http::INTERNAL_SERVER_ERROR )
);
}
}
return true;
}
/**
* Updates a meta value for an object.
*
* @since 4.7.0
*
* @param int $object_id Object ID to update.
* @param string $meta_key Key for the custom field.
* @param string $name Name for the field that is exposed in the REST API.
* @param mixed $value Updated value.
* @return bool|WP_Error True if the meta field was updated, WP_Error otherwise.
*/
protected function update_meta_value( $object_id, $meta_key, $name, $value ) {
$meta_type = $this->get_meta_type();
if ( ! current_user_can( "edit_{$meta_type}_meta", $object_id, $meta_key ) ) {
return new WP_Error(
'rest_cannot_update',
/* translators: %s: custom field key */
sprintf( __( 'Sorry, you are not allowed to edit the %s custom field.' ), $name ),
array( 'key' => $name, 'status' => rest_authorization_required_code() )
);
}
$meta_key = wp_slash( $meta_key );
$meta_value = wp_slash( $value );
// Do the exact same check for a duplicate value as in update_metadata() to avoid update_metadata() returning false.
$old_value = get_metadata( $meta_type, $object_id, $meta_key );
if ( 1 === count( $old_value ) ) {
if ( $old_value[0] === $meta_value ) {
return true;
}
}
if ( ! update_metadata( $meta_type, $object_id, $meta_key, $meta_value ) ) {
return new WP_Error(
'rest_meta_database_error',
__( 'Could not update meta value in database.' ),
array( 'key' => $name, 'status' => WP_Http::INTERNAL_SERVER_ERROR )
);
}
return true;
}
/**
* Retrieves all the registered meta fields.
*
* @since 4.7.0
*
* @return array Registered fields.
*/
protected function get_registered_fields() {
$registered = array();
foreach ( get_registered_meta_keys( $this->get_meta_type() ) as $name => $args ) {
if ( empty( $args['show_in_rest'] ) ) {
continue;
}
$rest_args = array();
if ( is_array( $args['show_in_rest'] ) ) {
$rest_args = $args['show_in_rest'];
}
$default_args = array(
'name' => $name,
'single' => $args['single'],
'type' => ! empty( $args['type'] ) ? $args['type'] : null,
'schema' => array(),
'prepare_callback' => array( $this, 'prepare_value' ),
);
$default_schema = array(
'type' => $default_args['type'],
'description' => empty( $args['description'] ) ? '' : $args['description'],
'default' => isset( $args['default'] ) ? $args['default'] : null,
);
$rest_args = array_merge( $default_args, $rest_args );
$rest_args['schema'] = array_merge( $default_schema, $rest_args['schema'] );
$type = ! empty( $rest_args['type'] ) ? $rest_args['type'] : null;
$type = ! empty( $rest_args['schema']['type'] ) ? $rest_args['schema']['type'] : $type;
if ( ! in_array( $type, array( 'string', 'boolean', 'integer', 'number' ) ) ) {
continue;
}
if ( empty( $rest_args['single'] ) ) {
$rest_args['schema']['items'] = array(
'type' => $rest_args['type'],
);
$rest_args['schema']['type'] = 'array';
}
$registered[ $name ] = $rest_args;
}
return $registered;
}
/**
* Retrieves the object's meta schema, conforming to JSON Schema.
*
* @since 4.7.0
*
* @return array Field schema data.
*/
public function get_field_schema() {
$fields = $this->get_registered_fields();
$schema = array(
'description' => __( 'Meta fields.' ),
'type' => 'object',
'context' => array( 'view', 'edit' ),
'properties' => array(),
'arg_options' => array(
'sanitize_callback' => null,
'validate_callback' => array( $this, 'check_meta_is_array' ),
),
);
foreach ( $fields as $args ) {
$schema['properties'][ $args['name'] ] = $args['schema'];
}
return $schema;
}
/**
* Prepares a meta value for output.
*
* Default preparation for meta fields. Override by passing the
* `prepare_callback` in your `show_in_rest` options.
*
* @since 4.7.0
*
* @param mixed $value Meta value from the database.
* @param WP_REST_Request $request Request object.
* @param array $args REST-specific options for the meta key.
* @return mixed Value prepared for output. If a non-JsonSerializable object, null.
*/
public static function prepare_value( $value, $request, $args ) {
$type = $args['schema']['type'];
// For multi-value fields, check the item type instead.
if ( 'array' === $type && ! empty( $args['schema']['items']['type'] ) ) {
$type = $args['schema']['items']['type'];
}
switch ( $type ) {
case 'string':
$value = (string) $value;
break;
case 'integer':
$value = (int) $value;
break;
case 'number':
$value = (float) $value;
break;
case 'boolean':
$value = (bool) $value;
break;
}
// Don't allow objects to be output.
if ( is_object( $value ) && ! ( $value instanceof JsonSerializable ) ) {
return null;
}
return $value;
}
/**
* Check the 'meta' value of a request is an associative array.
*
* @since 4.7.0
*
* @param mixed $value The meta value submitted in the request.
* @param WP_REST_Request $request Full details about the request.
* @param string $param The parameter name.
* @return WP_Error|string The meta array, if valid, otherwise an error.
*/
public function check_meta_is_array( $value, $request, $param ) {
if ( ! is_array( $value ) ) {
return false;
}
return $value;
}
}
class-wp-rest-term-meta-fields.php 0000666 00000001766 15123445157 0013143 0 ustar 00 <?php
/**
* REST API: WP_REST_Term_Meta_Fields class
*
* @package WordPress
* @subpackage REST_API
* @since 4.7.0
*/
/**
* Core class used to manage meta values for terms via the REST API.
*
* @since 4.7.0
*
* @see WP_REST_Meta_Fields
*/
class WP_REST_Term_Meta_Fields extends WP_REST_Meta_Fields {
/**
* Taxonomy to register fields for.
*
* @since 4.7.0
* @var string
*/
protected $taxonomy;
/**
* Constructor.
*
* @since 4.7.0
*
* @param string $taxonomy Taxonomy to register fields for.
*/
public function __construct( $taxonomy ) {
$this->taxonomy = $taxonomy;
}
/**
* Retrieves the object meta type.
*
* @since 4.7.0
*
* @return string The meta type.
*/
protected function get_meta_type() {
return 'term';
}
/**
* Retrieves the type for register_rest_field().
*
* @since 4.7.0
*
* @return string The REST field type.
*/
public function get_rest_field_type() {
return 'post_tag' === $this->taxonomy ? 'tag' : $this->taxonomy;
}
}
class-wp-rest-user-meta-fields.php 0000666 00000001243 15123445157 0013140 0 ustar 00 <?php
/**
* REST API: WP_REST_User_Meta_Fields class
*
* @package WordPress
* @subpackage REST_API
* @since 4.7.0
*/
/**
* Core class used to manage meta values for users via the REST API.
*
* @since 4.7.0
*
* @see WP_REST_Meta_Fields
*/
class WP_REST_User_Meta_Fields extends WP_REST_Meta_Fields {
/**
* Retrieves the object meta type.
*
* @since 4.7.0
*
* @return string The user meta type.
*/
protected function get_meta_type() {
return 'user';
}
/**
* Retrieves the type for register_rest_field().
*
* @since 4.7.0
*
* @return string The user REST field type.
*/
public function get_rest_field_type() {
return 'user';
}
}
class-wp-rest-comment-meta-fields.php 0000666 00000001276 15123445157 0013632 0 ustar 00 <?php
/**
* REST API: WP_REST_Comment_Meta_Fields class
*
* @package WordPress
* @subpackage REST_API
* @since 4.7.0
*/
/**
* Core class to manage comment meta via the REST API.
*
* @since 4.7.0
*
* @see WP_REST_Meta_Fields
*/
class WP_REST_Comment_Meta_Fields extends WP_REST_Meta_Fields {
/**
* Retrieves the object type for comment meta.
*
* @since 4.7.0
*
* @return string The meta type.
*/
protected function get_meta_type() {
return 'comment';
}
/**
* Retrieves the type for register_rest_field() in the context of comments.
*
* @since 4.7.0
*
* @return string The REST field type.
*/
public function get_rest_field_type() {
return 'comment';
}
}
class-gf-field-captcha.php 0000666 00000050651 15126403614 0011453 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_CAPTCHA extends GF_Field {
/**
* @var string
*/
public $type = 'captcha';
/**
* The reCAPTCHA API response.
*
* @var \stdClass
*/
private $response;
/**
* The reCAPTCHA site key.
*
* @var string
*/
private $site_key;
/**
* The reCAPTCHA secret key.
*
* @var string
*/
private $secret_key;
public function get_form_editor_field_title() {
return esc_attr__( 'CAPTCHA', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'captcha_type_setting',
'captcha_badge_setting',
'captcha_size_setting',
'captcha_fg_setting',
'captcha_bg_setting',
'captcha_language_setting',
'captcha_theme_setting',
'conditional_logic_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'description_setting',
'css_class_setting',
);
}
/**
* Validate the reCAPTCHA field.
*
* This method always gets called on the last page of a form, as well as on the page where the field is assigned.
*
* @since Unknown
*
* @param array|string $value The field value.
* @param array $form The form data.
*/
public function validate( $value, $form ) {
switch ( $this->captchaType ) {
case 'simple_captcha' :
if ( class_exists( 'ReallySimpleCaptcha' ) ) {
$prefix = $_POST[ "input_captcha_prefix_{$this->id}" ];
$captcha_obj = $this->get_simple_captcha();
if ( ! $captcha_obj->check( $prefix, str_replace( ' ', '', $value ) ) ) {
$this->set_failed_validation( esc_html__( "The CAPTCHA wasn't entered correctly. Go back and try it again.", 'gravityforms' ) );
}
//removes old files in captcha folder (older than 1 hour);
$captcha_obj->cleanup();
}
break;
case 'math' :
$prefixes = explode( ',', $_POST[ "input_captcha_prefix_{$this->id}" ] );
$captcha_obj = $this->get_simple_captcha();
//finding first number
for ( $first = 0; $first < 10; $first ++ ) {
if ( $captcha_obj->check( $prefixes[0], $first ) ) {
break;
}
}
//finding second number
for ( $second = 0; $second < 10; $second ++ ) {
if ( $captcha_obj->check( $prefixes[2], $second ) ) {
break;
}
}
//if it is a +, perform the sum
if ( $captcha_obj->check( $prefixes[1], '+' ) ) {
$result = $first + $second;
} else {
$result = $first - $second;
}
if ( intval( $result ) != intval( $value ) ) {
$this->set_failed_validation( esc_html__( "The CAPTCHA wasn't entered correctly. Go back and try it again.", 'gravityforms' ) );
}
//removes old files in captcha folder (older than 1 hour);
$captcha_obj->cleanup();
break;
default:
$this->validate_recaptcha( $form );
}
}
/**
* Validates the reCAPTCHA response.
*
* In our application flow, we create a decoded string out of the reCAPTCHA service response if the reCAPTCHA field
* is added to the form on a page other than the last page. We therefore first attempt to validate the decoded response,
* falling back to validating the reCAPTCHA with a request to Google.
*
* @see GF_Field_CAPTCHA::verify_decoded_response()
*
* @since unknown
*
* @param array $form The form data.
*
* @return bool
*/
public function validate_recaptcha( $form ) {
$response = $this->get_posted_recaptcha_response();
if ( ! ( $this->verify_decoded_response( $form, $response ) || $this->verify_recaptcha_response( $response ) ) ) {
$this->set_failed_validation( __( 'The reCAPTCHA was invalid. Go back and try it again.', 'gravityforms' ) );
return false;
}
return true;
}
/**
* Verifies that the decoded response meets the requirements for submitting the form.
*
* Returns false if the decoded response doesn't exist or the reCAPTCHA field is on the last page, as we'll want
* regular validation at that point instead.
*
* @since 2.4.24
*
* @param array $form The form data.
* @param string $response The encoded response to verify.
*
* @return bool
*/
private function verify_decoded_response( $form, $response ) {
$decoded_response = $this->get_decoded_recaptcha_response( $response );
// No decoded object.
if ( ! is_object( $decoded_response ) ) {
return false;
}
// Not a time that we need to verify the decoded object.
if ( ! GFFormDisplay::is_last_page( $form ) || $this->is_on_last_page( $form ) ) {
return false;
}
return (
$decoded_response->success === true
&& ! empty( $decoded_response->token )
&& gmdate( time() ) <= strtotime( '+1 day', strtotime( $decoded_response->challenge_ts ) )
);
}
/**
* Set validation failed on reCAPTCHA field.
*
* @since 2.4.24
*
* @param string $message The message to set if one does not already exist.
*/
private function set_failed_validation( $message ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? $message : $this->errorMessage;
}
/**
* Get the saved site key.
*
* @since 2.4.24
*
* @return string
*/
public function get_site_key() {
if ( ! $this->site_key ) {
$this->site_key = get_option( 'rg_gforms_captcha_public_key', '' );
}
return $this->site_key;
}
/**
* Get the saved secret key.
*
* @since 2.4.25
*
* @return string
*/
public function get_secret_key() {
if ( ! $this->secret_key ) {
$this->secret_key = get_option( 'rg_gforms_captcha_private_key', '' );
}
return $this->secret_key;
}
/**
* Get the value of the reCAPTCHA response input.
*
* When user clicks on the "I'm not a robot" box, the response token is populated into a hidden field by Google.
* If the current form is a multi-page form and the reCAPTCHA field is on a page other than the last page, this
* value will return an openssl encoded string with the Google reCAPTCHA validation data and some supplemental
* validation data instead.
*
* @see GF_Field_CAPTCHA::get_encoded_recaptcha_response()
*
* @since 2.4.24
*
* @return string
*/
private function get_posted_recaptcha_response() {
return sanitize_text_field( rgpost( 'g-recaptcha-response' ) );
}
/**
* Validate the reCAPTCHA token provided by Google.
*
* @since unknown
*
* @param string $response The token to verify.
* @param null $secret_key The secret key for reCAPTCHA verification.
*
* @return bool
*/
public function verify_recaptcha_response( $response, $secret_key = null ) {
$verify_url = 'https://www.google.com/recaptcha/api/siteverify';
if ( $secret_key == null ) {
$secret_key = $this->get_secret_key();
}
// pass secret key and token for verification of whether the response was valid
$response = wp_remote_post( $verify_url, array(
'method' => 'POST',
'body' => array(
'secret' => $secret_key,
'response' => $response
),
) );
if ( ! is_wp_error( $response ) ) {
$this->response = json_decode( wp_remote_retrieve_body( $response ) );
return $this->response->success == true;
} else {
GFCommon::log_debug( __METHOD__ . '(): Validating the reCAPTCHA response has failed due to the following: ' . $response->get_error_message() );
}
return false;
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = $form['id'];
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
switch ( $this->captchaType ) {
case 'simple_captcha' :
$size = empty($this->simpleCaptchaSize) ? 'medium' : esc_attr( $this->simpleCaptchaSize );
$captcha = $this->get_captcha();
$tabindex = $this->get_tabindex();
$dimensions = $is_entry_detail || $is_form_editor ? '' : "width='" . esc_attr( rgar( $captcha, 'width' ) ) . "' height='" . esc_attr( rgar( $captcha, 'height' ) ) . "'";
return "<div class='gfield_captcha_container'><img class='gfield_captcha' src='" . esc_url( rgar( $captcha, 'url' ) ) . "' alt='' {$dimensions} /><div class='gfield_captcha_input_container simple_captcha_{$size}'><input type='text' autocomplete='off' name='input_{$id}' id='{$field_id}' {$tabindex}/><input type='hidden' name='input_captcha_prefix_{$id}' value='" . esc_attr( rgar( $captcha, 'prefix' ) ) . "' /></div></div>";
break;
case 'math' :
$size = empty( $this->simpleCaptchaSize ) ? 'medium' : esc_attr( $this->simpleCaptchaSize );
$captcha_1 = $this->get_math_captcha( 1 );
$captcha_2 = $this->get_math_captcha( 2 );
$captcha_3 = $this->get_math_captcha( 3 );
$tabindex = $this->get_tabindex();
$dimensions = $is_entry_detail || $is_form_editor ? '' : "width='" . esc_attr( rgar( $captcha_1, 'width' ) ) . "' height='" . esc_attr( rgar( $captcha_1, 'height' ) ) . "'";
$prefix_value = rgar( $captcha_1, 'prefix' ) . ',' . rgar( $captcha_2, 'prefix' ) . ',' . rgar( $captcha_3, 'prefix' );
return "<div class='gfield_captcha_container'><img class='gfield_captcha' src='" . esc_url( rgar( $captcha_1, 'url' ) ) . "' alt='' {$dimensions} /><img class='gfield_captcha' src='" . esc_url( rgar( $captcha_2, 'url' ) ) . "' alt='' {$dimensions} /><img class='gfield_captcha' src='" . esc_url( rgar( $captcha_3, 'url' ) ) . "' alt='' {$dimensions} /><div class='gfield_captcha_input_container math_{$size}'><input type='text' autocomplete='off' name='input_{$id}' id='{$field_id}' {$tabindex}/><input type='hidden' name='input_captcha_prefix_{$id}' value='" . esc_attr( $prefix_value ) . "' /></div></div>";
break;
default:
$this->site_key = $this->get_site_key();
$this->secret_key = $this->get_secret_key();
$theme = in_array( $this->captchaTheme, array( 'blackglass', 'dark' ) ) ? 'dark' : 'light';
$type = get_option( 'rg_gforms_captcha_type' );
if ( $is_entry_detail || $is_form_editor ){
//for admin, show a thumbnail depending on chosen theme
if ( empty( $this->site_key ) || empty( $this->secret_key ) ) {
return "<div class='captcha_message'>" . __( 'To use the reCAPTCHA field you must do the following:', 'gravityforms' ) . "</div><div class='captcha_message'>1 - <a href='https://www.google.com/recaptcha/admin' target='_blank'>" . sprintf( __( 'Sign up%s for an API key pair for your site.', 'gravityforms' ), '</a>' ) . "</div><div class='captcha_message'>2 - " . sprintf( __( 'Enter your reCAPTCHA site and secret keys in the reCAPTCHA Settings section of the %sSettings page%s', 'gravityforms' ), "<a href='?page=gf_settings' target='_blank'>", '</a>' ) . '</div>';
}
$type_suffix = $type == 'invisible' ? 'invisible_' : '';
$alt = esc_attr__( 'An example of reCAPTCHA', 'gravityforms' );
return "<div class='ginput_container'><img class='gfield_captcha' src='" . GFCommon::get_base_url() . "/images/captcha_{$type_suffix}{$theme}.jpg' alt='{$alt}' /></div>";
}
$language = empty( $this->captchaLanguage ) ? 'en' : $this->captchaLanguage;
// script is queued for the footer with the language property specified
wp_enqueue_script( 'gform_recaptcha', 'https://www.google.com/recaptcha/api.js?hl=' . $language . '&render=explicit', array(), false, true );
add_action( 'wp_footer', array( $this, 'ensure_recaptcha_js' ), 21 );
add_action( 'gform_preview_footer', array( $this, 'ensure_recaptcha_js' ) );
$stoken = '';
if ( $this->use_stoken() ) {
// The secure token is a deprecated feature of the reCAPTCHA API.
// https://developers.google.com/recaptcha/docs/secure_token
$secure_token = self::create_recaptcha_secure_token( $this->secret_key );
$stoken = sprintf( 'data-stoken=\'%s\'', esc_attr( $secure_token ) );
}
$size = '';
$badge = '';
if ( $type == 'invisible' ) {
$size = "data-size='invisible'";
$badge = $this->captchaBadge ? $this->captchaBadge : 'bottomright';
$tabindex = -1;
} else {
$tabindex = GFCommon::$tab_index > 0 ? GFCommon::$tab_index++ : 0;
}
$output = "<div id='" . esc_attr( $field_id ) ."' class='ginput_container ginput_recaptcha' data-sitekey='" . esc_attr( $this->site_key ) . "' {$stoken} data-theme='" . esc_attr( $theme ) . "' data-tabindex='{$tabindex}' {$size} data-badge='{$badge}'></div>";
$recaptcha_response = $this->get_posted_recaptcha_response();
if ( ! $this->requires_encoding( $form, $recaptcha_response ) ) {
return $output;
}
ob_start();
?>
<input
type="hidden"
name="g-recaptcha-response"
value="<?php esc_attr_e( $this->get_encoded_recaptcha_response( $form, $recaptcha_response) ); ?>"
/>
<?php
return $output .= ob_get_clean();
}
}
/**
* Encode the reCAPTCHA response with details from Google.
*
* @since 2.4.24
*
* @param array $form The form data.
* @param string $response The posted response data.
*
* @return string
*/
private function get_encoded_recaptcha_response( $form, $response ) {
if ( ! $this->response ) {
return $response;
}
$this->response->token = $response;
return GFCommon::openssl_encrypt( base64_encode( json_encode( $this->response ) ), $this->secret_key );
}
/**
* Decode and return the value of g-recaptcha-response field.
*
* The first time this method is called, the $response parameter will be the result of the reCAPTCHA callback,
* and decryption will fail. On subsequent requests, it should contain an encoded string of the reCAPTCHA response
* and the original token used to make the request.
*
* @since 2.4.24
*
* @param string $response An openssl encoded string, or the reCAPTCHA token on the very first call.
*
* @return string
*/
private function get_decoded_recaptcha_response( $response ) {
$decoded_response = GFCommon::openssl_decrypt( $response, $this->get_secret_key() );
if ( ! $decoded_response ) {
return;
}
return json_decode( base64_decode( $decoded_response ) );
}
/**
* Check whether the reCAPTCHA response should be saved and encoded for validation on the final form page.
*
* @since 2.4.24
*
* @param array $form The form data.
* @param string $recaptcha_response The reCAPTCHA response.
*
* @return bool
*/
private function requires_encoding( $form, $recaptcha_response ) {
return $recaptcha_response && ! $this->failed_validation && GFFormDisplay::get_current_page( rgar( $form, 'id' ) ) != $this->pageNumber && ! $this->is_on_last_page( $form );
}
/**
* Returns true if this CAPTCHA field is on the last page of the given form.
*
* @since 2.4.24
*
* @param array $form The form data.
*
* @return bool
*/
private function is_on_last_page( $form ) {
$pages = GFAPI::get_fields_by_type( $form, array( 'page' ) );
return count( $pages ) + 1 === (int) $this->pageNumber;
}
public function ensure_recaptcha_js(){
?>
<script type="text/javascript">
( function( $ ) {
$( document ).bind( 'gform_post_render', function() {
var gfRecaptchaPoller = setInterval( function() {
if( ! window.grecaptcha || ! window.grecaptcha.render ) {
return;
}
renderRecaptcha();
clearInterval( gfRecaptchaPoller );
}, 100 );
} );
} )( jQuery );
</script>
<?php
}
public function get_captcha() {
if ( ! class_exists( 'ReallySimpleCaptcha' ) ) {
return array();
}
$captcha = $this->get_simple_captcha();
//If captcha folder does not exist and can't be created, return an empty captcha
if ( ! wp_mkdir_p( $captcha->tmp_dir ) ) {
return array();
}
$captcha->char_length = 5;
switch ( $this->simpleCaptchaSize ) {
case 'small' :
$captcha->img_size = array( 100, 28 );
$captcha->font_size = 18;
$captcha->base = array( 8, 20 );
$captcha->font_char_width = 17;
break;
case 'large' :
$captcha->img_size = array( 200, 56 );
$captcha->font_size = 32;
$captcha->base = array( 18, 42 );
$captcha->font_char_width = 35;
break;
default :
$captcha->img_size = array( 150, 42 );
$captcha->font_size = 26;
$captcha->base = array( 15, 32 );
$captcha->font_char_width = 25;
break;
}
if ( ! empty( $this->simpleCaptchaFontColor ) ) {
$captcha->fg = $this->hex2rgb( $this->simpleCaptchaFontColor );
}
if ( ! empty( $this->simpleCaptchaBackgroundColor ) ) {
$captcha->bg = $this->hex2rgb( $this->simpleCaptchaBackgroundColor );
}
$word = $captcha->generate_random_word();
$prefix = mt_rand();
$filename = $captcha->generate_image( $prefix, $word );
$url = RGFormsModel::get_upload_url( 'captcha' ) . '/' . $filename;
$path = $captcha->tmp_dir . $filename;
if ( GFCommon::is_ssl() && strpos( $url, 'http:' ) !== false ) {
$url = str_replace( 'http:', 'https:', $url );
}
return array( 'path' => $path, 'url' => $url, 'height' => $captcha->img_size[1], 'width' => $captcha->img_size[0], 'prefix' => $prefix );
}
public function get_simple_captcha() {
$captcha = new ReallySimpleCaptcha();
$captcha->tmp_dir = RGFormsModel::get_upload_path( 'captcha' ) . '/';
return $captcha;
}
public function get_math_captcha( $pos ) {
if ( ! class_exists( 'ReallySimpleCaptcha' ) ) {
return array();
}
$captcha = $this->get_simple_captcha();
//If captcha folder does not exist and can't be created, return an empty captcha
if ( ! wp_mkdir_p( $captcha->tmp_dir ) ) {
return array();
}
$captcha->char_length = 1;
if ( $pos == 1 || $pos == 3 ) {
$captcha->chars = '0123456789';
} else {
$captcha->chars = '+';
}
switch ( $this->simpleCaptchaSize ) {
case 'small' :
$captcha->img_size = array( 23, 28 );
$captcha->font_size = 18;
$captcha->base = array( 6, 20 );
$captcha->font_char_width = 17;
break;
case 'large' :
$captcha->img_size = array( 36, 56 );
$captcha->font_size = 32;
$captcha->base = array( 10, 42 );
$captcha->font_char_width = 35;
break;
default :
$captcha->img_size = array( 30, 42 );
$captcha->font_size = 26;
$captcha->base = array( 9, 32 );
$captcha->font_char_width = 25;
break;
}
if ( ! empty( $this->simpleCaptchaFontColor ) ) {
$captcha->fg = $this->hex2rgb( $this->simpleCaptchaFontColor );
}
if ( ! empty( $this->simpleCaptchaBackgroundColor ) ) {
$captcha->bg = $this->hex2rgb( $this->simpleCaptchaBackgroundColor );
}
$word = $captcha->generate_random_word();
$prefix = mt_rand();
$filename = $captcha->generate_image( $prefix, $word );
$url = RGFormsModel::get_upload_url( 'captcha' ) . '/' . $filename;
$path = $captcha->tmp_dir . $filename;
if ( GFCommon::is_ssl() && strpos( $url, 'http:' ) !== false ) {
$url = str_replace( 'http:', 'https:', $url );
}
return array( 'path' => $path, 'url' => $url, 'height' => $captcha->img_size[1], 'width' => $captcha->img_size[0], 'prefix' => $prefix );
}
private function hex2rgb( $color ) {
if ( $color[0] == '#' ) {
$color = substr( $color, 1 );
}
if ( strlen( $color ) == 6 ) {
list( $r, $g, $b ) = array(
$color[0] . $color[1],
$color[2] . $color[3],
$color[4] . $color[5],
);
} elseif ( strlen( $color ) == 3 ) {
list( $r, $g, $b ) = array( $color[0] . $color[0], $color[1] . $color[1], $color[2] . $color[2] );
} else {
return false;
}
$r = hexdec( $r );
$g = hexdec( $g );
$b = hexdec( $b );
return array( $r, $g, $b );
}
public function create_recaptcha_secure_token( $secret_key ) {
$secret_key = substr( hash( 'sha1', $secret_key, true ), 0, 16 );
$session_id = uniqid( 'recaptcha' );
$ts_ms = round( ( microtime( true ) - 1 ) * 1000 );
//create json string
$params = array( 'session_id' => $session_id, 'ts_ms' => $ts_ms );
$plaintext = json_encode( $params );
GFCommon::log_debug( 'recaptcha token parameters: ' . $plaintext );
//pad json string
$pad = 16 - ( strlen( $plaintext ) % 16 );
$padded = $plaintext . str_repeat( chr( $pad ), $pad );
//encrypt as 128
$cypher = defined( 'MCRYPT_RIJNDAEL_128' ) ? MCRYPT_RIJNDAEL_128 : false;
$encrypted = GFCommon::encrypt( $padded, $secret_key, $cypher );
$token = str_replace( array( '+', '/', '=' ), array( '-', '_', '' ), $encrypted );
GFCommon::log_debug( ' token being used is: ' . $token );
return $token;
}
public function use_stoken() {
// 'gform_recaptcha_keys_status' will be set to true if new keys have been entered
return ! get_option( 'gform_recaptcha_keys_status', false );
}
}
GF_Fields::register( new GF_Field_CAPTCHA() );
class-gf-field-multiselect.php 0000666 00000032207 15126403614 0012377 0 ustar 00 <?php
// If the GF_Field class isn't available, bail.
if ( ! class_exists( 'GFForms' ) ) {
die();
}
/**
* Class GF_Field_MultiSelect
*
* Allows the creation of multiselect fields.
*
* @since Unknown
*
* @uses GF_Field
*/
class GF_Field_MultiSelect extends GF_Field {
public $type = 'multiselect';
/**
* Returns the field title.
*
* @since Unknown
* @access public
*
* @return string The field title. Escaped.
*/
public function get_form_editor_field_title() {
return esc_attr__( 'Multi Select', 'gravityforms' );
}
/**
* Returns the class names of the settings which should be available on the field in the form editor.
*
* @since Unknown
* @access public
*
* @return array Settings available within the field editor.
*/
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'enable_enhanced_ui_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'choices_setting',
'rules_setting',
'visibility_setting',
'description_setting',
'css_class_setting',
);
}
/**
* Indicates this field type can be used when configuring conditional logic rules.
*
* @return bool
*/
public function is_conditional_logic_supported() {
return true;
}
/**
* Whether this field expects an array during submission.
*
* @since 2.4
*
* @return bool
*/
public function is_value_submission_array() {
return true;
}
/**
* Returns the field inner markup.
*
* @since Unknown
* @access public
*
* @uses GF_Field_MultiSelect::is_entry_detail()
* @uses GF_Field_MultiSelect::is_form_editor()
* @uses GF_Field_MultiSelect::get_conditional_logic_event()
* @uses GF_Field_MultiSelect::get_tabindex()
*
* @param array $form The Form Object currently being processed.
* @param string|array $value The field value. From default/dynamic population, $_POST, or a resumed incomplete submission.
* @param null|array $entry Null or the Entry Object currently being edited.
*
* @return string The field input HTML markup.
*/
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$class = esc_attr( $class );
$css_class = trim( $class . ' gfield_select' );
$tabindex = $this->get_tabindex();
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
/**
* Allow the placeholder used by the enhanced ui to be overridden
*
* @since 1.9.14 Third parameter containing the field ID was added.
* @since Unknown
*
* @param string $placeholder The placeholder text.
* @param integer $form_id The ID of the current form.
*/
$placeholder = gf_apply_filters( array(
'gform_multiselect_placeholder',
$form_id,
$this->id
), __( 'Click to select...', 'gravityforms' ), $form_id, $this );
$placeholder = $this->enableEnhancedUI ? "data-placeholder='" . esc_attr( $placeholder ) . "'" : '';
$size = $this->multiSelectSize;
if ( empty( $size ) ) {
$size = 7;
}
$size = esc_attr( $size );
return sprintf( "<div class='ginput_container ginput_container_multiselect'><select multiple='multiple' {$placeholder} size='{$size}' name='input_%d[]' id='%s' class='%s' $tabindex %s>%s</select></div>", $id, esc_attr( $field_id ), $css_class, $disabled_text, $this->get_choices( $value ) );
}
/**
* Helper for retrieving the markup for the choices.
*
* @since Unknown
* @access public
*
* @uses GFCommon::get_select_choices()
*
* @param string|array $value The field value. From default/dynamic population, $_POST, or a resumed incomplete submission.
*
* @return string Returns the choices available within the multi-select field.
*/
public function get_choices( $value ) {
$value = $this->to_array( $value );
return GFCommon::get_select_choices( $this, $value, false );
}
/**
* Format the entry value for display on the entries list page.
*
* @since Unknown
* @access public
*
* @param string|array $value The field value.
* @param array $entry The Entry Object currently being processed.
* @param string $field_id The field or input ID currently being processed.
* @param array $columns The properties for the columns being displayed on the entry list page.
* @param array $form The Form Object currently being processed.
*
* @return string $value The value of the field. Escaped.
*/
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
// Add space after comma-delimited values.
$value = implode( ', ', $this->to_array( $value ) );
return esc_html( $value );
}
/**
* Format the entry value for display on the entry detail page and for the {all_fields} merge tag.
*
* @since Unknown
* @access public
*
* @uses GFCommon::selection_display()
*
* @param string|array $value The field value.
* @param string $currency The entry currency code.
* @param bool|false $use_text When processing choice based fields should the choice text be returned instead of the value.
* @param string $format The format requested for the location the merge is being used. Possible values: html, text or url.
* @param string $media The location where the value will be displayed. Possible values: screen or email.
*
* @return string The list items, stored within an unordered list.
*/
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( empty( $value ) || ( $format == 'text' && $this->storageType !== 'json' ) ) {
return $value;
}
$items = $this->to_array( $value );
foreach ( $items as &$item ) {
$item = esc_html( GFCommon::selection_display( $item, $this, $currency, $use_text ) );
}
if ( $format === 'text' ) {
return GFCommon::implode_non_blank( ', ', $items );
}
return "<ul class='bulleted'><li>" . GFCommon::implode_non_blank( '</li><li>', $items ) . '</li></ul>';
}
/**
* Format the value before it is saved to the Entry Object.
*
* @since Unknown
* @access public
*
* @uses GF_Field_MultiSelect::sanitize_entry_value()
*
* @param array|string $value The value to be saved.
* @param array $form The Form Object currently being processed.
* @param string $input_name The input name used when accessing the $_POST.
* @param int $lead_id The ID of the Entry currently being processed.
* @param array $lead The Entry Object currently being processed.
*
* @return string $value The field value. Comma separated if an array.
*/
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
if ( is_array( $value ) ) {
foreach ( $value as &$v ) {
$v = $this->sanitize_entry_value( $v, $form['id'] );
}
} else {
$value = $this->sanitize_entry_value( $value, $form['id'] );
}
return empty( $value ) ? '' : $this->to_string( $value );
}
/**
* Format the entry value for when the field/input merge tag is processed.
*
* @since Unknown
* @access public
*
* @uses GFCommon::format_post_category()
* @uses GFCommon::format_variable_value()
* @uses GFCommon::selection_display()
* @uses GFCommon::implode_non_blank()
*
* @param string|array $value The field value. Depending on the location the merge tag is being used the following functions may have already been applied to the value: esc_html, nl2br, and urlencode.
* @param string $input_id The field or input ID from the merge tag currently being processed.
* @param array $entry The Entry Object currently being processed.
* @param array $form The Form Object currently being processed.
* @param string $modifier The merge tag modifier. e.g. value
* @param string|array $raw_value The raw field value from before any formatting was applied to $value.
* @param bool $url_encode Indicates if the urlencode function may have been applied to the $value.
* @param bool $esc_html Indicates if the esc_html function may have been applied to the $value.
* @param string $format The format requested for the location the merge is being used. Possible values: html, text or url.
* @param bool $nl2br Indicates if the nl2br function may have been applied to the $value.
*
* @return string $return The merge tag value.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
$items = $this->to_array( $raw_value );
$modifiers = $this->get_modifiers();
if ( $this->type == 'post_category' ) {
if ( is_array( $items ) ) {
$use_id = in_array( 'id', $modifiers );
foreach ( $items as &$item ) {
$cat = GFCommon::format_post_category( $item, $use_id );
$item = GFCommon::format_variable_value( $cat, $url_encode, $esc_html, $format );
}
}
} elseif ( ! in_array( 'value', $modifiers ) ) {
foreach ( $items as &$item ) {
$item = GFCommon::selection_display( $item, $this, rgar( $entry, 'currency' ), true );
$item = GFCommon::format_variable_value( $item, $url_encode, $esc_html, $format );
}
}
$return = GFCommon::implode_non_blank( ', ', $items );
if ( $format == 'html' || $esc_html ) {
$return = esc_html( $return );
}
return $return;
}
/**
* Format the entry value before it is used in entry exports and by framework add-ons using GFAddOn::get_field_value().
*
* @since Unknown
* @access public
*
* @uses GFCommon::selection_display()
* @uses GFCommon::implode_non_blank()
*
* @param array $entry The entry currently being processed.
* @param string $input_id The field or input ID.
* @param bool|false $use_text When processing choice based fields should the choice text be returned instead of the value.
* @param bool|false $is_csv Is the value going to be used in the .csv entries export?
*
* @return string $value The value of a field from an export file.
*/
public function get_value_export( $entry, $input_id = '', $use_text = false, $is_csv = false ) {
if ( empty( $input_id ) ) {
$input_id = $this->id;
}
$value = rgar( $entry, $input_id );
if ( ! empty( $value ) && ! $is_csv ) {
$items = $this->to_array( $value );
foreach ( $items as &$item ) {
$item = GFCommon::selection_display( $item, $this, rgar( $entry, 'currency' ), $use_text );
}
$value = GFCommon::implode_non_blank( ', ', $items );
} elseif ( $this->storageType === 'json' ) {
$items = json_decode( $value );
$value = GFCommon::implode_non_blank( ', ', $items );
}
return $value;
}
/**
* Converts an array to a string.
*
* @since 2.2.3.7 Changed access to public.
* @since 2.2
* @access public
*
* @uses \GF_Field_MultiSelect::$storageType
*
* @param array $value The array to convert to a string.
*
* @return string The converted string.
*/
public function to_string( $value ) {
if ( $this->storageType === 'json' ) {
return json_encode( $value );
} else {
return is_array( $value ) ? implode( ',', $value ) : $value;
}
}
/**
* Converts a string to an array.
*
* @since 2.2.3.7 Changed access to public.
* @since 2.2
* @access public
*
* @uses \GF_Field_MultiSelect::$storageType
*
* @param string $value A comma-separated or JSON string to convert.
*
* @return array The converted array.
*/
public function to_array( $value ) {
if ( empty( $value ) ) {
return array();
} elseif ( is_array( $value ) ) {
return $value;
} elseif ( $this->storageType !== 'json' || $value[0] !== '[' ) {
return array_map( 'trim', explode( ',', $value ) );
} else {
$json = json_decode( $value, true );
return $json == null ? array() : $json;
}
}
/**
* Forces settings into expected values while saving the form object.
*
* No escaping should be done at this stage to prevent double escaping on output.
*
* Currently called only for forms created after version 1.9.6.10.
*
* @since Unknown
* @access public
*
* @return void
*
*/
public function sanitize_settings() {
parent::sanitize_settings();
$this->enableEnhancedUI = (bool) $this->enableEnhancedUI;
$this->storageType = empty( $this->storageType ) || $this->storageType === 'json' ? $this->storageType : 'json';
if ( $this->type === 'post_category' ) {
$this->displayAllCategories = (bool) $this->displayAllCategories;
}
}
// # FIELD FILTER UI HELPERS ---------------------------------------------------------------------------------------
/**
* Returns the filter operators for the current field.
*
* @since 2.4
*
* @return array
*/
public function get_filter_operators() {
return array( 'contains' );
}
}
// Register the new field type.
GF_Fields::register( new GF_Field_MultiSelect() );
class-gf-field-creditcard.php 0000666 00000052355 15126403614 0012157 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_CreditCard extends GF_Field {
public $type = 'creditcard';
public function get_form_editor_field_title() {
return esc_attr__( 'Credit Card', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'force_ssl_field_setting',
'credit_card_style_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'sub_labels_setting',
'sub_label_placement_setting',
'label_placement_setting',
'admin_label_setting',
'rules_setting',
'description_setting',
'css_class_setting',
'credit_card_setting',
'input_placeholders_setting',
);
}
public function get_form_editor_button() {
return array(); // this button is conditionally added in the form detail page
}
public function validate( $value, $form ) {
$card_number = rgpost( 'input_' . $this->id . '_1' );
$expiration_date = rgpost( 'input_' . $this->id . '_2' );
$security_code = rgpost( 'input_' . $this->id . '_3' );
if ( $this->isRequired && ( empty( $card_number ) || empty( $security_code ) || empty( $expiration_date[0] ) || empty( $expiration_date[1] ) ) ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'Please enter your credit card information.', 'gravityforms' ) : $this->errorMessage;
} elseif ( ! empty( $card_number ) ) {
$card_type = GFCommon::get_card_type( $card_number );
if ( empty( $security_code ) ) {
$this->failed_validation = true;
$this->validation_message = esc_html__( "Please enter your card's security code.", 'gravityforms' );
} elseif ( ! $card_type ) {
$this->failed_validation = true;
$this->validation_message = esc_html__( 'Invalid credit card number.', 'gravityforms' );
} elseif ( ! $this->is_card_supported( $card_type['slug'] ) ) {
$this->failed_validation = true;
$this->validation_message = $card_type['name'] . ' ' . esc_html__( 'is not supported. Please enter one of the supported credit cards.', 'gravityforms' );
}
}
}
public function is_card_supported( $card_slug ) {
$supported_cards = $this->creditCards;
$default_cards = array( 'amex', 'discover', 'mastercard', 'visa' );
if ( ! empty( $supported_cards ) && in_array( $card_slug, $supported_cards ) ) {
return true;
} elseif ( empty( $supported_cards ) && in_array( $card_slug, $default_cards ) ) {
return true;
}
return false;
}
public function get_value_submission( $field_values, $get_from_post_global_var = true ) {
if ( $get_from_post_global_var ) {
$value[ $this->id . '.1' ] = $this->get_input_value_submission( 'input_' . $this->id . '_1', rgar( $this->inputs[0], 'name' ), $field_values, true );
$value[ $this->id . '.2' ] = $this->get_input_value_submission( 'input_' . $this->id . '_2', rgar( $this->inputs[1], 'name' ), $field_values, true );
$value[ $this->id . '.3' ] = $this->get_input_value_submission( 'input_' . $this->id . '_3', rgar( $this->inputs[3], 'name' ), $field_values, true );
$value[ $this->id . '.4' ] = $this->get_input_value_submission( 'input_' . $this->id . '_4', rgar( $this->inputs[4], 'name' ), $field_values, true );
$value[ $this->id . '.5' ] = $this->get_input_value_submission( 'input_' . $this->id . '_5', rgar( $this->inputs[5], 'name' ), $field_values, true );
} else {
$value = $this->get_input_value_submission( 'input_' . $this->id, $this->inputName, $field_values, $get_from_post_global_var );
}
return $value;
}
public function get_field_input( $form, $value = '', $entry = null ) {
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$form_id = $form['id'];
$id = intval( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$form_id = ( $is_entry_detail || $is_form_editor ) && empty( $form_id ) ? rgget( 'id' ) : $form_id;
$disabled_text = $is_form_editor ? "disabled='disabled'" : '';
$class_suffix = $is_entry_detail ? '_admin' : '';
$form_sub_label_placement = rgar( $form, 'subLabelPlacement' );
$field_sub_label_placement = $this->subLabelPlacement;
$is_sub_label_above = $field_sub_label_placement == 'above' || ( empty( $field_sub_label_placement ) && $form_sub_label_placement == 'above' );
$sub_label_class_attribute = $field_sub_label_placement == 'hidden_label' ? "class='hidden_sub_label screen-reader-text'" : '';
$card_number = '';
$card_name = '';
$expiration_month = '';
$expiration_year = '';
$security_code = '';
$autocomplete = RGFormsModel::is_html5_enabled() ? "autocomplete='off'" : '';
if ( is_array( $value ) ) {
$card_number = esc_attr( rgget( $this->id . '.1', $value ) );
$card_name = esc_attr( rgget( $this->id . '.5', $value ) );
$expiration_date = rgget( $this->id . '.2', $value );
if ( ! is_array( $expiration_date ) && ! empty( $expiration_date ) ) {
$expiration_date = explode( '/', $expiration_date );
}
if ( is_array( $expiration_date ) && count( $expiration_date ) == 2 ) {
$expiration_month = $expiration_date[0];
$expiration_year = $expiration_date[1];
}
$security_code = esc_attr( rgget( $this->id . '.3', $value ) );
}
$action = ! ( $is_entry_detail || $is_form_editor ) ? "gformMatchCard(\"{$field_id}_1\");" : '';
$onchange = "onchange='{$action}'";
$onkeyup = "onkeyup='{$action}'";
$card_icons = '';
$cards = GFCommon::get_card_types();
$card_style = $this->creditCardStyle ? $this->creditCardStyle : 'style1';
foreach ( $cards as $card ) {
$style = '';
if ( $this->is_card_supported( $card['slug'] ) ) {
$print_card = true;
} elseif ( $is_form_editor || $is_entry_detail ) {
$print_card = true;
$style = "style='display:none;'";
} else {
$print_card = false;
}
if ( $print_card ) {
$card_icons .= "<div class='gform_card_icon gform_card_icon_{$card['slug']}' {$style}>{$card['name']}</div>";
}
}
$payment_methods = apply_filters( 'gform_payment_methods', array(), $this, $form_id );
$payment_options = '';
if ( is_array( $payment_methods ) ) {
foreach ( $payment_methods as $payment_method ) {
$checked = rgpost( 'gform_payment_method' ) == $payment_method['key'] ? "checked='checked'" : '';
$payment_options .= "<div class='gform_payment_option gform_payment_{$payment_method['key']}'><input type='radio' name='gform_payment_method' value='{$payment_method['key']}' id='gform_payment_method_{$payment_method['key']}' onclick='gformToggleCreditCard();' onkeypress='gformToggleCreditCard();' {$checked}/> {$payment_method['label']}</div>";
}
}
$checked = rgpost( 'gform_payment_method' ) == 'creditcard' || rgempty( 'gform_payment_method' ) ? "checked='checked'" : '';
$card_radio_button = empty( $payment_options ) ? '' : "<input type='radio' name='gform_payment_method' id='gform_payment_method_creditcard' value='creditcard' onclick='gformToggleCreditCard();' onkeypress='gformToggleCreditCard();' {$checked}/>";
$card_icons = "{$payment_options}<div class='gform_card_icon_container gform_card_icon_{$card_style}'>{$card_radio_button}{$card_icons}</div>";
//card number fields
$tabindex = $this->get_tabindex();
$card_number_field_input = GFFormsModel::get_input( $this, $this->id . '.1' );
$html5_output = ! is_admin() && GFFormsModel::is_html5_enabled() ? "pattern='[0-9]*' title='" . esc_attr__( 'Only digits are allowed', 'gravityforms' ) . "'" : '';
$card_number_label = rgar( $card_number_field_input, 'customLabel' ) != '' ? $card_number_field_input['customLabel'] : esc_html__( 'Card Number', 'gravityforms' );
$card_number_label = gf_apply_filters( array( 'gform_card_number', $form_id ), $card_number_label, $form_id );
$card_number_placeholder = $this->get_input_placeholder_attribute( $card_number_field_input );
if ( $is_sub_label_above ) {
$card_field = "<span class='ginput_full{$class_suffix}' id='{$field_id}_1_container' >
{$card_icons}
<label for='{$field_id}_1' id='{$field_id}_1_label' {$sub_label_class_attribute}>{$card_number_label}</label>
<input type='text' name='input_{$id}.1' id='{$field_id}_1' value='{$card_number}' {$tabindex} {$disabled_text} {$onchange} {$onkeyup} {$autocomplete} {$html5_output} {$card_number_placeholder}/>
</span>";
} else {
$card_field = "<span class='ginput_full{$class_suffix}' id='{$field_id}_1_container' >
{$card_icons}
<input type='text' name='input_{$id}.1' id='{$field_id}_1' value='{$card_number}' {$tabindex} {$disabled_text} {$onchange} {$onkeyup} {$autocomplete} {$html5_output} {$card_number_placeholder}/>
<label for='{$field_id}_1' id='{$field_id}_1_label' {$sub_label_class_attribute}>{$card_number_label}</label>
</span>";
}
//expiration date field
$expiration_month_tab_index = $this->get_tabindex();
$expiration_year_tab_index = $this->get_tabindex();
$expiration_month_input = GFFormsModel::get_input( $this, $this->id . '.2_month' );
$expiration_month_placeholder = $this->get_input_placeholder_value( $expiration_month_input );
$expiration_year_input = GFFormsModel::get_input( $this, $this->id . '.2_year' );
$expiration_year_placeholder = $this->get_input_placeholder_value( $expiration_year_input );
$expiration_months = $this->get_expiration_months( $expiration_month, $expiration_month_placeholder );
$expiration_years = $this->get_expiration_years( $expiration_year, $expiration_year_placeholder );
$expiration_label = rgar( $expiration_month_input, 'customLabel' ) != '' ? $expiration_month_input['customLabel'] : esc_html__( 'Expiration Date', 'gravityforms' );
$expiration_label = gf_apply_filters( array( 'gform_card_expiration', $form_id ), $expiration_label, $form_id );
if ( $is_sub_label_above ) {
$expiration_field = "<span class='ginput_full{$class_suffix} ginput_cardextras' id='{$field_id}_2_container'>
<span class='ginput_cardinfo_left{$class_suffix}' id='{$field_id}_2_cardinfo_left'>
<span class='ginput_card_expiration_container ginput_card_field'>
<label for='{$field_id}_2_month' {$sub_label_class_attribute}>{$expiration_label}</label>
<select name='input_{$id}.2[]' id='{$field_id}_2_month' {$expiration_month_tab_index} {$disabled_text} class='ginput_card_expiration ginput_card_expiration_month'>
{$expiration_months}
</select>
<select name='input_{$id}.2[]' id='{$field_id}_2_year' {$expiration_year_tab_index} {$disabled_text} class='ginput_card_expiration ginput_card_expiration_year'>
{$expiration_years}
</select>
</span>
</span>";
} else {
$expiration_field = "<span class='ginput_full{$class_suffix} ginput_cardextras' id='{$field_id}_2_container'>
<span class='ginput_cardinfo_left{$class_suffix}' id='{$field_id}_2_cardinfo_left'>
<span class='ginput_card_expiration_container ginput_card_field'>
<select name='input_{$id}.2[]' id='{$field_id}_2_month' {$expiration_month_tab_index} {$disabled_text} class='ginput_card_expiration ginput_card_expiration_month'>
{$expiration_months}
</select>
<select name='input_{$id}.2[]' id='{$field_id}_2_year' {$expiration_year_tab_index} {$disabled_text} class='ginput_card_expiration ginput_card_expiration_year'>
{$expiration_years}
</select>
<label for='{$field_id}_2_month' {$sub_label_class_attribute}>{$expiration_label}</label>
</span>
</span>";
}
//security code field
$tabindex = $this->get_tabindex();
$security_code_field_input = GFFormsModel::get_input( $this, $this->id . '.3' );
$security_code_label = rgar( $security_code_field_input, 'customLabel' ) != '' ? $security_code_field_input['customLabel'] : esc_html__( 'Security Code', 'gravityforms' );
$security_code_label = gf_apply_filters( array( 'gform_card_security_code', $form_id ), $security_code_label, $form_id );
$html5_output = GFFormsModel::is_html5_enabled() ? "pattern='[0-9]*' title='" . esc_attr__( 'Only digits are allowed', 'gravityforms' ) . "'" : '';
$security_code_placeholder = $this->get_input_placeholder_attribute( $security_code_field_input );
if ( $is_sub_label_above ) {
$security_field = "<span class='ginput_cardinfo_right{$class_suffix}' id='{$field_id}_2_cardinfo_right'>
<label for='{$field_id}_3' {$sub_label_class_attribute}>$security_code_label</label>
<input type='text' name='input_{$id}.3' id='{$field_id}_3' {$tabindex} {$disabled_text} class='ginput_card_security_code' value='{$security_code}' {$autocomplete} {$html5_output} {$security_code_placeholder} />
<span class='ginput_card_security_code_icon'> </span>
</span>
</span>";
} else {
$security_field = "<span class='ginput_cardinfo_right{$class_suffix}' id='{$field_id}_2_cardinfo_right'>
<input type='text' name='input_{$id}.3' id='{$field_id}_3' {$tabindex} {$disabled_text} class='ginput_card_security_code' value='{$security_code}' {$autocomplete} {$html5_output} {$security_code_placeholder}/>
<span class='ginput_card_security_code_icon'> </span>
<label for='{$field_id}_3' {$sub_label_class_attribute}>$security_code_label</label>
</span>
</span>";
}
$tabindex = $this->get_tabindex();
$card_name_field_input = GFFormsModel::get_input( $this, $this->id . '.5' );
$card_name_label = rgar( $card_name_field_input, 'customLabel' ) != '' ? $card_name_field_input['customLabel'] : esc_html__( 'Cardholder Name', 'gravityforms' );
$card_name_label = gf_apply_filters( array( 'gform_card_name', $form_id ), $card_name_label, $form_id );
$card_name_placeholder = $this->get_input_placeholder_attribute( $card_name_field_input );
if ( $is_sub_label_above ) {
$card_name_field = "<span class='ginput_full{$class_suffix}' id='{$field_id}_5_container'>
<label for='{$field_id}_5' id='{$field_id}_5_label' {$sub_label_class_attribute}>{$card_name_label}</label>
<input type='text' name='input_{$id}.5' id='{$field_id}_5' value='{$card_name}' {$tabindex} {$disabled_text} {$card_name_placeholder}/>
</span>";
} else {
$card_name_field = "<span class='ginput_full{$class_suffix}' id='{$field_id}_5_container'>
<input type='text' name='input_{$id}.5' id='{$field_id}_5' value='{$card_name}' {$tabindex} {$disabled_text} {$card_name_placeholder}/>
<label for='{$field_id}_5' id='{$field_id}_5_label' {$sub_label_class_attribute}>{$card_name_label}</label>
</span>";
}
return "<div class='ginput_complex{$class_suffix} ginput_container ginput_container_creditcard' id='{$field_id}'>" . $card_field . $expiration_field . $security_field . $card_name_field . ' </div>';
}
public function get_field_label_class(){
return 'gfield_label gfield_label_before_complex';
}
private function get_expiration_months( $selected_month, $placeholder ) {
if ( empty( $placeholder ) ) {
$placeholder = esc_html__( 'Month', 'gravityforms' );
}
$str = "<option value=''>{$placeholder}</option>";
for ( $i = 1; $i < 13; $i ++ ) {
$selected = intval( $selected_month ) == $i ? "selected='selected'" : '';
$month = str_pad( $i, 2, '0', STR_PAD_LEFT );
$str .= "<option value='{$i}' {$selected}>{$month}</option>";
}
return $str;
}
private function get_expiration_years( $selected_year, $placeholder ) {
if ( empty( $placeholder ) ) {
$placeholder = esc_html__( 'Year', 'gravityforms' );
}
$str = "<option value=''>{$placeholder}</option>";
$year = intval( date( 'Y' ) );
for ( $i = $year; $i < ( $year + 20 ); $i ++ ) {
$selected = intval( $selected_year ) == $i ? "selected='selected'" : '';
$str .= "<option value='{$i}' {$selected}>{$i}</option>";
}
return $str;
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( is_array( $value ) ) {
$card_number = trim( rgget( $this->id . '.1', $value ) );
$card_type = trim( rgget( $this->id . '.4', $value ) );
$separator = $format == 'html' ? '<br/>' : "\n";
return empty( $card_number ) ? '' : $card_type . $separator . $card_number;
} else {
return '';
}
}
public function get_form_inline_script_on_page_render( $form ) {
$field_id = "input_{$form['id']}_{$this->id}";
if ( $this->forceSSL && ! GFCommon::is_ssl() && ! GFCommon::is_preview() ) {
$script = "document.location.href='" . esc_js( RGFormsModel::get_current_page_url( true ) ) . "';";
} else {
$script = "jQuery(document).ready(function(){ { gformMatchCard(\"{$field_id}_1\"); } } );";
}
$card_rules = $this->get_credit_card_rules();
$script = "if(!window['gf_cc_rules']){window['gf_cc_rules'] = new Array(); } window['gf_cc_rules'] = " . GFCommon::json_encode( $card_rules ) . "; $script";
return $script;
}
public function get_credit_card_rules() {
$cards = GFCommon::get_card_types();
//$supported_cards = //TODO: Only include enabled cards
$rules = array();
foreach ( $cards as $card ) {
$prefixes = explode( ',', $card['prefixes'] );
foreach ( $prefixes as $prefix ) {
$rules[ $card['slug'] ][] = $prefix;
}
}
return $rules;
}
public function get_entry_inputs() {
$inputs = array();
// only store month and card number input values
foreach ( $this->inputs as $input ) {
if ( in_array( $input['id'], array( $this->id . '.1', $this->id . '.4' ) ) ) {
$inputs[] = $input;
}
}
return $inputs;
}
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
//saving last 4 digits of credit card
list( $input_token, $field_id_token, $input_id ) = rgexplode( '_', $input_name, 3 );
if ( $input_id == '1' ) {
$value = str_replace( ' ', '', $value );
$card_number_length = strlen( $value );
$value = substr( $value, - 4, 4 );
$value = str_pad( $value, $card_number_length, 'X', STR_PAD_LEFT );
} elseif ( $input_id == '4' ) {
$value = rgpost( "input_{$field_id_token}_4" );
if ( ! $value ) {
$card_number = rgpost( "input_{$field_id_token}_1" );
$card_type = GFCommon::get_card_type( $card_number );
$value = $card_type ? $card_type['name'] : '';
}
} else {
$value = '';
}
return $this->sanitize_entry_value( $value, $form['id'] );
}
/**
* Upgrades inputs, if needed.
*
* @since 2.1.2.7
* @access public
* @see GF_Field::post_convert_field()
*
* @uses GF_Field::post_convert_field()
* @uses GF_Field_CreditCard::maybe_upgrade_inputs()
*
* @return void
*/
public function post_convert_field() {
parent::post_convert_field();
$this->maybe_upgrade_inputs();
}
/**
* GF1.8 and earlier used 5 inputs (1 input for the expiration date); GF1.9 changed to 6 inputs (the expiration month and year now separate); upgrade those fields still using the older configuration.
*/
public function maybe_upgrade_inputs() {
$inputs = $this->inputs;
$exp_input = $inputs[1];
$exp_id = $this->id . '.2';
if ( count( $inputs ) == 5 && $exp_input['id'] == $exp_id ) {
$new_inputs = array(
array(
'id' => $exp_id . '_month',
'label' => esc_html__( 'Expiration Month', 'gravityforms' ),
'defaultLabel' => $exp_input['label']
),
array(
'id' => $exp_id . '_year',
'label' => esc_html__( 'Expiration Year', 'gravityforms' ),
)
);
array_splice( $inputs, 1, 1, $new_inputs );
$this->inputs = $inputs;
}
}
}
GF_Fields::register( new GF_Field_CreditCard() );
class-gf-field-radio.php 0000666 00000031131 15126403614 0011136 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Radio extends GF_Field {
public $type = 'radio';
public function get_form_editor_field_title() {
return esc_attr__( 'Radio Buttons', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'choices_setting',
'rules_setting',
'visibility_setting',
'duplicate_setting',
'description_setting',
'css_class_setting',
'other_choice_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
public function validate( $value, $form ) {
if ( $this->isRequired && $this->enableOtherChoice && rgpost( "input_{$this->id}" ) == 'gf_other_choice' ) {
if ( empty( $value ) || strtolower( $value ) == strtolower( GFCommon::get_other_choice_value( $this ) ) ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'This field is required.', 'gravityforms' ) : $this->errorMessage;
}
}
}
public function get_first_input_id( $form ) {
return '';
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = $form['id'];
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
return sprintf( "<div class='ginput_container ginput_container_radio'><ul class='gfield_radio' id='%s'>%s</ul></div>", $field_id, $this->get_radio_choices( $value, $disabled_text, $form_id ) );
}
public function get_radio_choices( $value = '', $disabled_text = '', $form_id = 0 ) {
$choices = '';
if ( is_array( $this->choices ) ) {
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$is_admin = $is_entry_detail || $is_form_editor;
$field_choices = $this->choices;
$needs_other_choice = $this->enableOtherChoice;
$editor_limited = false;
$choice_id = 0;
$count = 1;
foreach ( $field_choices as $choice ) {
if ( rgar( $choice, 'isOtherChoice' ) ) {
if ( ! $needs_other_choice ) {
continue;
}
$needs_other_choice = false;
}
$choices .= $this->get_choice_html( $choice, $choice_id, $value, $disabled_text, $is_admin );
if ( $is_form_editor && $count >= 5 ) {
$editor_limited = true;
break;
}
$count ++;
}
if ( $needs_other_choice ) {
$other_choice = array(
'text' => GFCommon::get_other_choice_value( $this ),
'value' => 'gf_other_choice',
'isSelected' => false,
'isOtherChoice' => true,
);
$field_choices[] = $other_choice;
if ( ! $is_form_editor || ! $editor_limited ) {
$choices .= $this->get_choice_html( $other_choice, $choice_id, $value, $disabled_text, $is_admin );
$count ++;
}
}
$total = sizeof( $field_choices );
if ( $is_form_editor && ( $count < $total ) ) {
$choices .= "<li class='gchoice_total'>" . sprintf( esc_html__( '%d of %d items shown. Edit field to view all', 'gravityforms' ), $count, $total ) . '</li>';
}
}
/**
* Allows the HTML for multiple choices to be overridden.
*
* @since unknown
*
* @param string $choices The choices HTML.
* @param GF_Field_Radio $field The current field object.
*/
return gf_apply_filters( array( 'gform_field_choices', $this->formId ), $choices, $this );
}
/**
* Returns the choice HTML.
*
* @since 2.4.17
*
* @param array $choice The choice properties.
* @param int &$choice_id The choice number.
* @param string $value The current field value.
* @param string $disabled_text The disabled attribute or an empty string.
* @param bool $is_admin Indicates if this is the form editor or entry detail page.
*
* @return string
*/
public function get_choice_html( $choice, &$choice_id, $value, $disabled_text, $is_admin ) {
$form_id = absint( $this->formId );
if ( $is_admin || $form_id == 0 ) {
$id = $this->id . '_' . $choice_id ++;
} else {
$id = $form_id . '_' . $this->id . '_' . $choice_id ++;
}
$field_value = ! empty( $choice['value'] ) || $this->enableChoiceValue ? $choice['value'] : $choice['text'];
if ( $this->enablePrice ) {
$price = rgempty( 'price', $choice ) ? 0 : GFCommon::to_number( rgar( $choice, 'price' ) );
$field_value .= '|' . $price;
}
if ( rgblank( $value ) && rgget( 'view' ) != 'entry' ) {
$checked = rgar( $choice, 'isSelected' ) ? "checked='checked'" : '';
} else {
$checked = GFFormsModel::choice_value_match( $this, $choice, $value ) ? "checked='checked'" : '';
}
$tabindex = $this->get_tabindex();
$label = sprintf( "<label for='choice_%s' id='label_%s'>%s</label>", $id, $id, $choice['text'] );
$input_focus = '';
// Handle 'other' choice.
if ( $this->enableOtherChoice && rgar( $choice, 'isOtherChoice' ) ) {
$other_default_value = empty( $choice['text'] ) ? GFCommon::get_other_choice_value( $this ) : $choice['text'];
$onfocus = ! $is_admin ? 'jQuery(this).prev("input")[0].click(); if(jQuery(this).val() == "' . $other_default_value . '") { jQuery(this).val(""); }' : '';
$onblur = ! $is_admin ? 'if(jQuery(this).val().replace(" ", "") == "") { jQuery(this).val("' . $other_default_value . '"); }' : '';
$input_focus = ! $is_admin ? "onfocus=\"jQuery(this).next('input').focus();\"" : '';
$value_exists = GFFormsModel::choices_value_match( $this, $this->choices, $value );
if ( $value == 'gf_other_choice' && rgpost( "input_{$this->id}_other" ) ) {
$other_value = rgpost( "input_{$this->id}_other" );
} elseif ( ! $value_exists && ! empty( $value ) ) {
$other_value = $value;
$value = 'gf_other_choice';
$checked = "checked='checked'";
} else {
$other_value = $other_default_value;
}
$label = "<input id='input_{$this->formId}_{$this->id}_other' name='input_{$this->id}_other' type='text' value='" . esc_attr( $other_value ) . "' aria-label='" . esc_attr__( 'Other', 'gravityforms' ) . "' onfocus='$onfocus' onblur='$onblur' $tabindex $disabled_text />";
}
$choice_markup = sprintf( "<li class='gchoice_$id'><input name='input_%d' type='radio' value='%s' %s id='choice_%s' $tabindex %s %s />%s</li>", $this->id, esc_attr( $field_value ), $checked, $id, $disabled_text, $input_focus, $label );
/**
* Allows the HTML for a specific choice to be overridden.
*
* @since 1.9.6
* @since 1.9.12 Added the field specific version.
* @since 2.4.17 Moved from GF_Field_Radio::get_radio_choices().
*
* @param string $choice_markup The choice HTML.
* @param array $choice The choice properties.
* @param GF_Field_Radio $field The current field object.
* @param string $value The current field value.
*/
return gf_apply_filters( array( 'gform_field_choice_markup_pre_render', $this->formId, $this->id ), $choice_markup, $choice, $this, $value );
}
public function get_value_default() {
return $this->is_form_editor() ? $this->defaultValue : GFCommon::replace_variables_prepopulate( $this->defaultValue );
}
public function get_value_submission( $field_values, $get_from_post_global_var = true ) {
$value = $this->get_input_value_submission( 'input_' . $this->id, $this->inputName, $field_values, $get_from_post_global_var );
if ( $value == 'gf_other_choice' ) {
//get value from text box
$value = $this->get_input_value_submission( 'input_' . $this->id . '_other', $this->inputName, $field_values, $get_from_post_global_var );
}
return $value;
}
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
return wp_kses_post( GFCommon::selection_display( $value, $this, $entry['currency'] ) );
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
return wp_kses_post( GFCommon::selection_display( $value, $this, $currency, $use_text ) );
}
/**
* Gets merge tag values.
*
* @since Unknown
* @access public
*
* @uses GFCommon::to_money()
* @uses GFCommon::format_post_category()
* @uses GFFormsModel::is_field_hidden()
* @uses GFFormsModel::get_choice_text()
* @uses GFCommon::format_variable_value()
* @uses GFCommon::implode_non_blank()
*
* @param array|string $value The value of the input.
* @param string $input_id The input ID to use.
* @param array $entry The Entry Object.
* @param array $form The Form Object
* @param string $modifier The modifier passed.
* @param array|string $raw_value The raw value of the input.
* @param bool $url_encode If the result should be URL encoded.
* @param bool $esc_html If the HTML should be escaped.
* @param string $format The format that the value should be.
* @param bool $nl2br If the nl2br function should be used.
*
* @return string The processed merge tag.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
$modifiers = $this->get_modifiers();
$use_value = in_array( 'value', $modifiers );
$format_currency = ! $use_value && in_array( 'currency', $modifiers );
$use_price = $format_currency || ( ! $use_value && in_array( 'price', $modifiers ) );
if ( is_array( $raw_value ) && (string) intval( $input_id ) != $input_id ) {
$items = array( $input_id => $value ); // Float input Ids. (i.e. 4.1 ). Used when targeting specific checkbox items.
} elseif ( is_array( $raw_value ) ) {
$items = $raw_value;
} else {
$items = array( $input_id => $raw_value );
}
$ary = array();
foreach ( $items as $input_id => $item ) {
if ( $use_value ) {
list( $val, $price ) = rgexplode( '|', $item, 2 );
} elseif ( $use_price ) {
list( $name, $val ) = rgexplode( '|', $item, 2 );
if ( $format_currency ) {
$val = GFCommon::to_money( $val, rgar( $entry, 'currency' ) );
}
} elseif ( $this->type == 'post_category' ) {
$use_id = strtolower( $modifier ) == 'id';
$item_value = GFCommon::format_post_category( $item, $use_id );
$val = RGFormsModel::is_field_hidden( $form, $this, array(), $entry ) ? '' : $item_value;
} else {
$val = RGFormsModel::is_field_hidden( $form, $this, array(), $entry ) ? '' : RGFormsModel::get_choice_text( $this, $raw_value, $input_id );
}
$ary[] = GFCommon::format_variable_value( $val, $url_encode, $esc_html, $format );
}
return GFCommon::implode_non_blank( ', ', $ary );
}
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
if ( $this->enableOtherChoice && $value == 'gf_other_choice' ) {
$value = rgpost( "input_{$this->id}_other" );
}
$value = $this->sanitize_entry_value( $value, $form['id'] );
return $value;
}
public function allow_html() {
return true;
}
public function get_value_export( $entry, $input_id = '', $use_text = false, $is_csv = false ) {
if ( empty( $input_id ) ) {
$input_id = $this->id;
}
$value = rgar( $entry, $input_id );
return $is_csv ? $value : GFCommon::selection_display( $value, $this, rgar( $entry, 'currency' ), $use_text );
}
/**
* Strip scripts and some HTML tags.
*
* @param string $value The field value to be processed.
* @param int $form_id The ID of the form currently being processed.
*
* @return string
*/
public function sanitize_entry_value( $value, $form_id ) {
if ( is_array( $value ) ) {
return '';
}
$allowable_tags = $this->get_allowable_tags( $form_id );
if ( $allowable_tags !== true ) {
$value = strip_tags( $value, $allowable_tags );
}
$allowed_protocols = wp_allowed_protocols();
$value = wp_kses_no_null( $value, array( 'slash_zero' => 'keep' ) );
$value = wp_kses_hook( $value, 'post', $allowed_protocols );
$value = wp_kses_split( $value, 'post', $allowed_protocols );
return $value;
}
// # FIELD FILTER UI HELPERS ---------------------------------------------------------------------------------------
/**
* Returns the filter operators for the current field.
*
* @since 2.4
*
* @return array
*/
public function get_filter_operators() {
$operators = $this->type == 'product' ? array( 'is' ) : array( 'is', 'isnot', '>', '<' );
return $operators;
}
}
GF_Fields::register( new GF_Field_Radio() );
class-gf-field-post-content.php 0000666 00000002530 15126403614 0012476 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
require_once( plugin_dir_path( __FILE__ ) . 'class-gf-field-textarea.php' );
class GF_Field_Post_Content extends GF_Field_Textarea {
public $type = 'post_content';
public function get_form_editor_field_title() {
return esc_attr__( 'Body', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'post_content_template_setting',
'post_status_setting',
'post_category_setting',
'post_author_setting',
'post_format_setting',
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'maxlen_setting',
'rules_setting',
'visibility_setting',
'default_value_textarea_setting',
'placeholder_textarea_setting',
'description_setting',
'css_class_setting',
'rich_text_editor_setting',
);
}
public function allow_html() {
return true;
}
/**
* Filter the rich_editing option for the current user.
*
* @since 2.2.5.14
*
* @param string $value The value of the rich_editing option for the current user.
*
* @return string
*/
public function filter_user_option_rich_editing( $value ) {
return is_user_logged_in() ? $value : 'true';
}
}
GF_Fields::register( new GF_Field_Post_Content() );
class-gf-field-calculation.php 0000666 00000012353 15126403614 0012343 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Calculation extends GF_Field {
public $type = 'calculation';
function get_form_editor_field_settings() {
return array(
'disable_quantity_setting',
'rules_setting',
'duplicate_setting',
'calculation_setting',
'conditional_logic_field_setting',
);
}
public function get_form_editor_button() {
return array();
}
public function validate( $value, $form ) {
$quantity_id = $this->id . '.3';
$quantity = rgget( $quantity_id, $value );
if ( $this->isRequired && rgblank( $quantity ) && ! $this->disableQuantity ) {
$this->failed_validation = true;
$this->validation_message = empty($this->errorMessage) ? esc_html__( 'This field is required.', 'gravityforms' ) : $this->errorMessage;
} elseif ( ! empty( $quantity ) && ( ! is_numeric( $quantity ) || intval( $quantity ) != floatval( $quantity ) || intval( $quantity ) < 0 ) ) {
$this->failed_validation = true;
$this->validation_message = esc_html__( 'Please enter a valid quantity', 'gravityforms' );
}
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = $form['id'];
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$product_name = ! is_array( $value ) || empty( $value[ $this->id . '.1' ] ) ? esc_attr( $this->label ) : esc_attr( $value[ $this->id . '.1' ] );
$price = ! is_array( $value ) || empty( $value[ $this->id . '.2' ] ) ? $this->basePrice : esc_attr( $value[ $this->id . '.2' ] );
$quantity = is_array( $value ) ? esc_attr( $value[ $this->id . '.3' ] ) : '';
if ( empty( $price ) ) {
$price = 0;
}
$has_quantity = sizeof( GFCommon::get_product_fields_by_type( $form, array( 'quantity' ), $this->id ) ) > 0;
if ( $has_quantity ) {
$this->disableQuantity = true;
}
$currency = $is_entry_detail && ! empty( $entry ) ? $entry['currency'] : '';
$quantity_field = '';
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$qty_input_type = GFFormsModel::is_html5_enabled() ? 'number' : 'text';
$product_quantity_sub_label = gf_apply_filters( array( 'gform_product_quantity', $form_id, $this->id ), esc_html__( 'Quantity:', 'gravityforms' ), $form_id );
if ( $is_entry_detail || $is_form_editor ) {
$style = $this->disableQuantity ? "style='display:none;'" : '';
$quantity_field = " <span class='ginput_quantity_label' {$style}>{$product_quantity_sub_label}</span> <input type='{$qty_input_type}' name='input_{$id}.3' value='{$quantity}' id='ginput_quantity_{$form_id}_{$this->id}' class='ginput_quantity' size='10' {$disabled_text}/>";
} elseif ( ! $this->disableQuantity ) {
$tabindex = $this->get_tabindex();
$quantity_field .= " <span class='ginput_quantity_label'>" . $product_quantity_sub_label . "</span> <input type='{$qty_input_type}' name='input_{$id}.3' value='{$quantity}' id='ginput_quantity_{$form_id}_{$this->id}' class='ginput_quantity' size='10' {$tabindex} {$disabled_text}/>";
} else {
if ( ! is_numeric( $quantity ) ) {
$quantity = 1;
}
if ( ! $has_quantity ) {
$quantity_field .= "<input type='hidden' name='input_{$id}.3' value='{$quantity}' class='ginput_quantity_{$form_id}_{$this->id} gform_hidden' />";
}
}
return "<div class='ginput_container ginput_container_product_calculation'>
<input type='hidden' name='input_{$id}.1' value='{$product_name}' class='gform_hidden' />
<span class='ginput_product_price_label'>" . gf_apply_filters( array( 'gform_product_price', $form_id, $this->id ), esc_html__( 'Price', 'gravityforms' ), $form_id ) . ":</span> <span class='ginput_product_price' id='{$field_id}'>" . esc_html( GFCommon::to_money( $price, $currency ) ) . "</span>
<input type='hidden' name='input_{$id}.2' id='ginput_base_price_{$form_id}_{$this->id}' class='gform_hidden' value='" . esc_attr( $price ) . "'/>
{$quantity_field}
</div>";
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( is_array( $value ) && ! empty( $value ) ) {
$product_name = trim( $value[ $this->id . '.1' ] );
$price = trim( $value[ $this->id . '.2' ] );
$quantity = trim( $value[ $this->id . '.3' ] );
$product = $product_name . ', ' . esc_html__( 'Qty: ', 'gravityforms' ) . $quantity . ', ' . esc_html__( 'Price: ', 'gravityforms' ) . $price;
return $product;
} else {
return '';
}
}
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
// ignore submitted value and recalculate price in backend
list( $prefix, $field_id, $input_id ) = rgexplode( '_', $input_name, 3 );
if ( $input_id == 2 ) {
$currency = new RGCurrency( GFCommon::get_currency() );
$lead = empty( $lead ) ? RGFormsModel::get_lead( $lead_id ) : $lead;
$value = $currency->to_money( GFCommon::calculate( $this, $form, $lead ) );
}
return $value;
}
public function sanitize_settings() {
parent::sanitize_settings();
$this->enableCalculation = (bool) $this->enableCalculation;
}
}
GF_Fields::register( new GF_Field_Calculation() ); class-gf-field-hidden.php 0000666 00000004764 15126403614 0011307 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Hidden extends GF_Field {
public $type = 'hidden';
public function get_form_editor_field_title() {
return esc_attr__( 'Hidden', 'gravityforms' );
}
public function is_conditional_logic_supported(){
return true;
}
function get_form_editor_field_settings() {
return array(
'prepopulate_field_setting',
'label_setting',
'default_value_setting',
);
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = $form['id'];
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$field_type = $is_entry_detail || $is_form_editor ? 'text' : 'hidden';
$class_attribute = $is_entry_detail || $is_form_editor ? '' : "class='gform_hidden'";
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
return sprintf( "<input name='input_%d' id='%s' type='$field_type' {$class_attribute} {$required_attribute} {$invalid_attribute} value='%s' %s/>", $id, $field_id, esc_attr( $value ), $disabled_text );
}
public function get_field_content( $value, $force_frontend_label, $form ) {
$form_id = $form['id'];
$admin_buttons = $this->get_admin_buttons();
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$is_admin = $is_entry_detail || $is_form_editor;
$field_label = $this->get_field_label( $force_frontend_label, $value );
$field_id = $is_admin || $form_id == 0 ? "input_{$this->id}" : 'input_' . $form_id . "_{$this->id}";
$field_content = ! $is_admin ? '{FIELD}' : $field_content = sprintf( "%s<label class='gfield_label' for='%s'>%s</label>{FIELD}", $admin_buttons, $field_id, esc_html( $field_label ) );
return $field_content;
}
// # FIELD FILTER UI HELPERS ---------------------------------------------------------------------------------------
/**
* Returns the filter operators for the current field.
*
* @since 2.4
*
* @return array
*/
public function get_filter_operators() {
$operators = parent::get_filter_operators();
$operators[] = 'contains';
return $operators;
}
}
GF_Fields::register( new GF_Field_Hidden() );
class-gf-field-html.php 0000666 00000004601 15126403614 0011006 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_HTML extends GF_Field {
public $type = 'html';
public function get_form_editor_field_title() {
return esc_attr__( 'HTML', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'content_setting',
'disable_margins_setting',
'conditional_logic_field_setting',
'label_setting',
'css_class_setting',
);
}
public function get_field_input( $form, $value = '', $entry = null ) {
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$content = $is_entry_detail || $is_form_editor ? "<div class='gf-html-container'><span class='gf_blockheader'>
<i class='fa fa-code fa-lg'></i> " . esc_html__( 'HTML Content', 'gravityforms' ) .
'</span><span>' . esc_html__( 'This is a content placeholder. HTML content is not displayed in the form admin. Preview this form to view the content.', 'gravityforms' ) . '</span></div>'
: $this->content;
$content = GFCommon::replace_variables_prepopulate( $content ); // adding support for merge tags
// adding support for shortcodes
$content = $this->do_shortcode( $content );
return $content;
}
public function get_field_content( $value, $force_frontend_label, $form ) {
$form_id = $form['id'];
$admin_buttons = $this->get_admin_buttons();
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$is_admin = $is_entry_detail || $is_form_editor;
$field_label = $this->get_field_label( $force_frontend_label, $value );
$field_id = $is_admin || $form_id == 0 ? "input_{$this->id}" : 'input_' . $form_id . "_{$this->id}";
$field_content = ! $is_admin ? '{FIELD}' : $field_content = sprintf( "%s<label class='gfield_label' for='%s'>%s</label>{FIELD}", $admin_buttons, $field_id, esc_html( $field_label ) );
return $field_content;
}
public function sanitize_settings() {
parent::sanitize_settings();
$this->content = GFCommon::maybe_wp_kses( $this->content );
}
public function do_shortcode( $content ){
if( isset($GLOBALS['wp_embed']) ) {
// adds support for the [embed] shortcode
$content = $GLOBALS['wp_embed']->run_shortcode( $content );
}
// executes all other shortcodes
$content = do_shortcode( $content );
return $content;
}
}
GF_Fields::register( new GF_Field_HTML() );
class-gf-field-consent.php 0000666 00000041572 15126403614 0011523 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
/**
* The Consent Field keeps track of exactly what the user consented to. The consent value ("1"), checkbox label and the Form revision ID
* are all stored in the entry meta table in separate input values when consent is given.
*
* @since 2.4
*
* Class GF_Field_Consent
*/
class GF_Field_Consent extends GF_Field {
/**
* Declare the field type.
*
* @since 2.4
*
* @var string
*/
public $type = 'consent';
/**
* Checked indicator URL.
*
* @since 2.4
*
* @var string
*/
public $checked_indicator_url = '';
/**
* Checked indicator image markup.
*
* @since 2.4
*
* @var string
*/
public $checked_indicator_markup = '';
/**
* GF_Field_Consent constructor.
*
* @since 2.4
*
* @param array $data Data needed when initiate the class.
*/
public function __construct( $data = array() ) {
parent::__construct( $data );
/**
* Filters the consent checked indicator (image) URL.
*
* @since 2.4
*
* @param string $url Image URL.
*/
$this->checked_indicator_url = apply_filters( 'gform_consent_checked_indicator', GFCommon::get_base_url() . '/images/tick.png' );
/**
* Filters the consent checked indicator (image) element.
*
* @since 2.4
*
* @param string $tag Image tag.
*/
$this->checked_indicator_markup = apply_filters( 'gform_consent_checked_indicator_markup', '<img src="' . esc_url( $this->checked_indicator_url ) . '" />' );
}
/**
* Returns the field title.
*
* @since 2.4
*
* @return string
*/
public function get_form_editor_field_title() {
return esc_attr__( 'Consent', 'gravityforms' );
}
/**
* Returns the field button properties for the form editor. The array contains two elements:
* 'group' => 'standard_fields' // or 'advanced_fields', 'post_fields', 'pricing_fields'
* 'text' => 'Button text'
*
* @since 2.4
*
* @return array
*/
public function get_form_editor_button() {
return array(
'group' => 'advanced_fields',
'text' => $this->get_form_editor_field_title(),
);
}
/**
* Returns the class names of the settings which should be available on the field in the form editor.
*
* @since 2.4
*
* @return array
*/
public function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'checkbox_label_setting',
'rules_setting',
'visibility_setting',
'description_setting',
'css_class_setting',
);
}
/**
* Indicate if this field type can be used when configuring conditional logic rules.
*
* @since 2.4
*
* @return bool
*/
public function is_conditional_logic_supported() {
return true;
}
/**
* Returns the field inner markup.
*
* @since 2.4
*
* @param array $form The Form Object currently being processed.
* @param array $value The field value. From default/dynamic population, $_POST, or a resumed incomplete submission.
* @param null|array $entry Null or the Entry Object currently being edited.
*
* @return string
*/
public function get_field_input( $form, $value = array(), $entry = null ) {
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$is_admin = $is_form_editor || $is_entry_detail;
$html_input_type = 'checkbox';
$id = (int) $this->id;
$tabindex = $this->get_tabindex();
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$target_input_id = parent::get_first_input_id( $form );
$for_attribute = empty( $target_input_id ) ? '' : "for='{$target_input_id}'";
$label_class_attribute = 'class="gfield_consent_label"';
$required_div = ( $this->labelPlacement === 'hidden_label' && ( $is_admin || $this->isRequired ) ) ? sprintf( "<span class='gfield_required'>%s</span>", $this->isRequired ? '*' : '' ) : '';
if ( $is_admin && ! GFCommon::is_entry_detail_edit() ) {
$checkbox_label = ! is_array( $value ) || empty( $value[ $id . '.2' ] ) ? $this->checkboxLabel : $value[ $id . '.2' ];
$revision_id = ! is_array( $value ) || empty( $value[ $id . '.3' ] ) ? GFFormsModel::get_latest_form_revisions_id( $form['id'] ) : $value[ $id . '.3' ];
$value = ! is_array( $value ) || empty( $value[ $id . '.1' ] ) ? '0' : esc_attr( $value[ $id . '.1' ] );
} else {
$checkbox_label = trim( $this->checkboxLabel );
$revision_id = GFFormsModel::get_latest_form_revisions_id( $form['id'] );
// We compare if the description text from different revisions has been changed.
$current_description = $this->get_field_description_from_revision( $revision_id );
$submitted_description = $this->get_field_description_from_revision( $value[ $id . '.3' ] );
$value = ! is_array( $value ) || empty( $value[ $id . '.1' ] ) || ( $checkbox_label !== $value[ $id . '.2' ] ) || ( $current_description !== $submitted_description ) ? '0' : esc_attr( $value[ $id . '.1' ] );
}
$checked = $is_form_editor ? '' : checked( '1', $value, false );
$aria_describedby = '';
$description = $is_entry_detail ? $this->get_field_description_from_revision( $revision_id ) : $this->description;
if ( ! empty( $description ) ) {
$aria_describedby = "aria-describedby='gfield_consent_description_{$form['id']}_{$this->id}'";
}
$input = "<input name='input_{$id}.1' id='{$target_input_id}' type='{$html_input_type}' value='1' {$tabindex} {$aria_describedby} {$required_attribute} {$invalid_attribute} {$disabled_text} {$checked} /> <label {$label_class_attribute} {$for_attribute} >{$checkbox_label}</label>{$required_div}";
$input .= "<input type='hidden' name='input_{$id}.2' value='" . esc_attr( $checkbox_label ) . "' class='gform_hidden' />";
$input .= "<input type='hidden' name='input_{$id}.3' value='" . esc_attr( $revision_id ) . "' class='gform_hidden' />";
if ( $is_entry_detail ) {
$input .= $this->get_description( $this->get_field_description_from_revision( $revision_id ), '' );
}
return sprintf( "<div class='ginput_container ginput_container_consent'>%s</div>", $input );
}
/**
* Returns the input ID to be assigned to the field label for attribute.
*
* @since 2.4
*
* @param array $form The Form Object currently being processed.
*
* @return string
*/
public function get_first_input_id( $form ) {
return '';
}
/**
* Returns the markup for the field description.
*
* @since 2.4
*
* @param string $description The field description.
* @param string $css_class The css class to be assigned to the description container.
*
* @return string
*/
public function get_description( $description, $css_class ) {
if ( ! empty( $description ) ) {
$id = "gfield_consent_description_{$this->formId}_{$this->id}";
$css_class .= ' gfield_consent_description';
return "<div class='$css_class' id='$id'>" . nl2br( $description ) . '</div>';
}
return parent::get_description( $description, $css_class );
}
/**
* Return the result (bool) by setting $this->failed_validation.
* Return the validation message (string) by setting $this->validation_message.
*
* @since 2.4
*
* @param string|array $value The field value from get_value_submission().
* @param array $form The Form Object currently being processed.
*/
public function validate( $value, $form ) {
$consent = rgget( $this->id . '.1', $value );
if ( $this->isRequired && rgblank( $consent ) ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'This field is required.', 'gravityforms' ) : $this->errorMessage;
}
}
/**
* Sanitize and format the value before it is saved to the Entry Object.
* We also add the value of inputs .2 and .3 here since they are not displayed in the form.
*
* @since 2.4
*
* @param string $value The value to be saved.
* @param array $form The Form Object currently being processed.
* @param string $input_name The input name used when accessing the $_POST.
* @param int $lead_id The ID of the Entry currently being processed.
* @param array $lead The Entry Object currently being processed.
*
* @return array|string The safe value.
*/
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
list( $input, $field_id, $input_id ) = rgexplode( '_', $input_name, 3 );
switch ( $input_id ) {
case '1':
$value = ( ! empty( $value ) ) ? '1' : '';
break;
case '2':
$value = ( $lead[ $field_id . '.1' ] === '1' ) ? $value : '';
break;
case '3':
$value = ( $lead[ $field_id . '.1' ] === '1' ) ? $value : '';
break;
}
return $value;
}
/**
* Set the values of consent field inputs in merge tags.
*
* @since 2.4
*
* @param string|array $value The field value. Depending on the location the merge tag is being used the following functions may have already been applied to the value: esc_html, nl2br, and urlencode.
* @param string $input_id The field or input ID from the merge tag currently being processed.
* @param array $entry The Entry Object currently being processed.
* @param array $form The Form Object currently being processed.
* @param string $modifier The merge tag modifier. e.g. value.
* @param string|array $raw_value The raw field value from before any formatting was applied to $value.
* @param bool $url_encode Indicates if the urlencode function may have been applied to the $value.
* @param bool $esc_html Indicates if the esc_html function may have been applied to the $value.
* @param string $format The format requested for the location the merge is being used. Possible values: html, text or url.
* @param bool $nl2br Indicates if the nl2br function may have been applied to the $value.
*
* @return string
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
list( $field_id, $input_id ) = explode( '.', $input_id );
switch ( $input_id ) {
case '1':
$value = ! rgblank( $value ) ? $this->checked_indicator_markup : '';
break;
case '3':
$value = ! rgblank( $value ) ? $this->get_field_description_from_revision( $value ) : '';
if ( $value !== '' && $nl2br ) {
$value = nl2br( $value );
}
break;
}
return $value;
}
/**
* Format the entry value for display on the entries list page.
*
* @since 2.4
*
* @param string|array $value The field value.
* @param array $entry The Entry Object currently being processed.
* @param string $field_id The field or input ID currently being processed.
* @param array $columns The properties for the columns being displayed on the entry list page.
* @param array $form The Form Object currently being processed.
*
* @return string
*/
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
list( $field_id, $input_id ) = explode( '.', $field_id );
switch ( $input_id ) {
case '1':
$value = ! rgblank( $value ) ? $this->checked_indicator_markup : '';
$value .= ! rgblank( $value ) ? ' ' . trim( $entry[ $this->id . '.2' ] ) : '';
break;
}
return $value;
}
/**
* Format the entry value for display on the entry detail page and for the {all_fields} merge tag.
*
* @since 2.4
*
* @param string|array $value The field value.
* @param string $currency The entry currency code.
* @param bool|false $use_text When processing choice based fields should the choice text be returned instead of the value.
* @param string $format The format requested for the location the merge is being used. Possible values: html, text or url.
* @param string $media The location where the value will be displayed. Possible values: screen or email.
*
* @return string
*/
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
$return = '';
if ( is_array( $value ) && ! empty( $value ) ) {
$consent = trim( $value[ $this->id . '.1' ] );
$text = trim( $value[ $this->id . '.2' ] );
$revision_id = absint( trim( $value[ $this->id . '.3' ] ) );
if ( ! rgblank( $consent ) ) {
$return = $this->checked_indicator_markup;
$return .= ' ' . wp_kses_post( $text );
// checking revisions.
$description = $this->get_field_description_from_revision( $revision_id );
if ( ! empty( $description ) ) {
$return .= '<br /><div class="gfield_consent_description">' . nl2br( $description ) . '</div>';
}
}
}
return $return;
}
/**
* Format the entry value before it is used in entry exports and by framework add-ons using GFAddOn::get_field_value().
*
* For CSV export return a string or array.
*
* @since 2.4
*
* @param array $entry The entry currently being processed.
* @param string $input_id The field or input ID.
* @param bool|false $use_text When processing choice based fields should the choice text be returned instead of the value.
* @param bool|false $is_csv Is the value going to be used in the .csv entries export.
*
* @return string|array
*/
public function get_value_export( $entry, $input_id = '', $use_text = false, $is_csv = false ) {
if ( empty( $input_id ) ) {
return '';
}
$value = parent::get_value_export( $entry, $input_id, $use_text, $is_csv );
list( $field_id, $input_id ) = rgexplode( '.', $input_id, 2 );
switch ( $input_id ) {
case '1':
$value = ! rgblank( $value ) ? esc_html__( 'Checked', 'gravityforms' ) : esc_html__( 'Not Checked', 'gravityforms' );
break;
case '3':
$value = ! rgblank( $value ) ? $this->get_field_description_from_revision( $value ) : '';
break;
}
return $value;
}
/**
* Forces settings into expected values while saving the form object.
*
* No escaping should be done at this stage to prevent double escaping on output.
*
* @since 2.4
*/
public function sanitize_settings() {
parent::sanitize_settings();
$this->checkboxLabel = $this->maybe_wp_kses( $this->checkboxLabel );
}
/**
* Returns the filter settings for the current field.
*
* If overriding to add custom settings call the parent method first to get the default settings.
*
* @since 2.4
*
* @return array
*/
public function get_filter_settings() {
$filter_settings = array(
'key' => $this->id . '.1',
'text' => GFFormsModel::get_label( $this ),
'preventMultiple' => false,
'operators' => $this->get_filter_operators(),
);
$values = $this->get_filter_values();
if ( ! empty( $values ) ) {
$filter_settings['values'] = $values;
}
return $filter_settings;
}
/**
* Returns the filter operators for the current field.
*
* @since 2.4
*
* @return array
*/
public function get_filter_operators() {
$operators = array( 'is', 'isnot' );
return $operators;
}
/**
* Returns the filters values setting for the current field.
*
* @since 2.4
*
* @return array
*/
public function get_filter_values() {
$choices = array(
array(
'value' => '1',
'text' => esc_html__( 'Checked', 'gravityforms' ),
),
);
return $choices;
}
/**
* Get consent description from the form revision.
*
* @since 2.4
*
* @param int $revision_id Revision ID.
*
* @return string
*/
public function get_field_description_from_revision( $revision_id ) {
global $wpdb;
$revisions_table_name = GFFormsModel::get_form_revisions_table_name();
$display_meta = $wpdb->get_var( $wpdb->prepare( "SELECT display_meta FROM $revisions_table_name WHERE form_id=%d AND id=%d", $this->formId, $revision_id ) );
$value = '';
$is_entry_detail = $this->is_entry_detail();
if ( ! empty( $display_meta ) ) {
$display_meta_array = json_decode( $display_meta, true );
foreach ( $display_meta_array['fields'] as $field ) {
if ( $field['id'] === $this->id ) {
$value = $field['description'];
break;
}
}
} else {
$value = ( ! empty( $this->description ) ) ? $this->description : '';
}
if ( $is_entry_detail ) {
$value = $this->maybe_wp_kses( $value );
}
return $value;
}
}
GF_Fields::register( new GF_Field_Consent() );
class-gf-field.php 0000666 00000136507 15126403614 0010057 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
/**
* Class GF_Field
*
* This class provides the base functionality for developers when creating new fields for Gravity Forms. It facilitates the following:
* Adding a button for the field to the form editor
* Defining the field title to be used in the form editor
* Defining which settings should be present when editing the field
* Registering the field as compatible with conditional logic
* Outputting field scripts to the form editor and front-end
* Defining the field appearance on the front-end, in the form editor and on the entry detail page
* Validating the field during submission
* Saving the entry value
* Defining how the entry value is displayed when merge tags are processed, on the entries list and entry detail pages
* Defining how the entry value should be formatted when used in csv exports and by framework based add-ons
*/
class GF_Field extends stdClass implements ArrayAccess {
const SUPPRESS_DEPRECATION_NOTICE = true;
private static $deprecation_notice_fired = false;
private $_is_entry_detail = null;
/**
* An array of properties used to help define and determine the context for the field.
* As this is private, it won't be available in any json_encode() output and consequently not saved in the Form array.
*
* @since 2.3
*
* @private
*
* @var array
*/
private $_context_properties = array();
/**
* @var array $_merge_tag_modifiers An array of modifiers specified on the field or all_fields merge tag being processed.
*/
private $_merge_tag_modifiers = array();
public function __construct( $data = array() ) {
if ( empty( $data ) ) {
return;
}
foreach ( $data as $key => $value ) {
$this->{$key} = $value;
}
}
/**
* Fires the deprecation notice only once per page. Not fired during AJAX requests.
*
* @param string $offset The array key being accessed.
*/
private function maybe_fire_array_access_deprecation_notice( $offset ) {
if ( self::SUPPRESS_DEPRECATION_NOTICE ) {
return;
};
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
return;
}
if ( ! self::$deprecation_notice_fired ) {
_deprecated_function( "Array access to the field object is now deprecated. Further notices will be suppressed. \$field['" . $offset . "']", '2.0', 'the object operator e.g. $field->' . $offset );
self::$deprecation_notice_fired = true;
}
}
/**
* Handles array notation
*
* @param mixed $offset
*
* @return bool
*/
public function offsetExists( $offset ) {
$this->maybe_fire_array_access_deprecation_notice( $offset );
return isset( $this->$offset );
}
public function offsetGet( $offset ) {
$this->maybe_fire_array_access_deprecation_notice( $offset );
if ( ! isset( $this->$offset ) ) {
$this->$offset = '';
}
return $this->$offset;
}
public function offsetSet( $offset, $data ) {
$this->maybe_fire_array_access_deprecation_notice( $offset );
if ( $offset === null ) {
$this[] = $data;
} else {
$this->$offset = $data;
}
}
public function offsetUnset( $offset ) {
$this->maybe_fire_array_access_deprecation_notice( $offset );
unset( $this->$offset );
}
public function __isset( $key ) {
return isset( $this->$key );
}
public function __set( $key, $value ) {
switch( $key ) {
case '_context_properties' :
_doing_it_wrong( '$field->_context_properties', 'Use $field->get_context_property() instead.', '2.3' );
break;
case 'adminOnly':
// intercept 3rd parties trying to set the adminOnly property and convert to visibility property
$this->visibility = $value ? 'administrative' : 'visible';
break;
default:
$this->$key = $value;
}
}
/**
* The getter method of the field property.
*
* @since unknown
* @since 2.4.19 Add whitelist for the size property.
*
* @param string $key The field property.
*
* @return bool|mixed
*/
public function &__get( $key ) {
switch ( $key ) {
case '_context_properties' :
_doing_it_wrong( '$field->_context_properties', 'Use $field->get_context_property() instead.', '2.3' );
$value = false;
return $value;
case 'adminOnly' :
// intercept 3rd parties trying to get the adminOnly property and fetch visibility property instead
$value = $this->visibility == 'administrative'; // set and return variable to avoid notice
return $value;
case 'size':
$value = '';
if ( isset( $this->size ) ) {
$value = GFCommon::whitelist( $this->size, array( 'small', 'medium', 'large' ) );
}
return $value;
default:
if ( ! isset( $this->$key ) ) {
$this->$key = '';
}
}
return $this->$key;
}
public function __unset( $key ) {
unset( $this->$key );
}
public function set_context_property( $property_key, $value ) {
$this->_context_properties[ $property_key ] = $value;
}
public function get_context_property( $property_key ) {
return isset( $this->_context_properties[ $property_key ] ) ? $this->_context_properties[ $property_key ] : null;
}
// # FORM EDITOR & FIELD MARKUP -------------------------------------------------------------------------------------
/**
* Returns the field title.
*
* @return string
*/
public function get_form_editor_field_title() {
return $this->type;
}
/**
* Returns the field button properties for the form editor. The array contains two elements:
* 'group' => 'standard_fields' // or 'advanced_fields', 'post_fields', 'pricing_fields'
* 'text' => 'Button text'
*
* Built-in fields don't need to implement this because the buttons are added in sequence in GFFormDetail
*
* @return array
*/
public function get_form_editor_button() {
return array(
'group' => 'standard_fields',
'text' => $this->get_form_editor_field_title()
);
}
/**
* Returns the class names of the settings which should be available on the field in the form editor.
*
* @return array
*/
public function get_form_editor_field_settings() {
return array();
}
/**
* Override to indicate if this field type can be used when configuring conditional logic rules.
*
* @return bool
*/
public function is_conditional_logic_supported() {
return false;
}
/**
* Returns the scripts to be included for this field type in the form editor.
*
* @return string
*/
public function get_form_editor_inline_script_on_page_render() {
return '';
}
/**
* Returns the scripts to be included with the form init scripts on the front-end.
*
* @param array $form The Form Object currently being processed.
*
* @return string
*/
public function get_form_inline_script_on_page_render( $form ) {
return '';
}
/**
* Returns the field inner markup.
*
* @param array $form The Form Object currently being processed.
* @param string|array $value The field value. From default/dynamic population, $_POST, or a resumed incomplete submission.
* @param null|array $entry Null or the Entry Object currently being edited.
*
* @return string
*/
public function get_field_input( $form, $value = '', $entry = null ) {
return '';
}
/**
* Returns the field markup; including field label, description, validation, and the form editor admin buttons.
*
* The {FIELD} placeholder will be replaced in GFFormDisplay::get_field_content with the markup returned by GF_Field::get_field_input().
*
* @param string|array $value The field value. From default/dynamic population, $_POST, or a resumed incomplete submission.
* @param bool $force_frontend_label Should the frontend label be displayed in the admin even if an admin label is configured.
* @param array $form The Form Object currently being processed.
*
* @return string
*/
public function get_field_content( $value, $force_frontend_label, $form ) {
$form_id = (int) rgar( $form, 'id' );
$field_label = $this->get_field_label( $force_frontend_label, $value );
$validation_message_id = 'validation_message_' . $form_id . '_' . $this->id;
$validation_message = ( $this->failed_validation && ! empty( $this->validation_message ) ) ? sprintf( "<div id='%s' class='gfield_description validation_message' aria-live='polite'>%s</div>", $validation_message_id, $this->validation_message ) : '';
$is_form_editor = $this->is_form_editor();
$is_entry_detail = $this->is_entry_detail();
$is_admin = $is_form_editor || $is_entry_detail;
$required_div = $is_admin || $this->isRequired ? sprintf( "<span class='gfield_required'>%s</span>", $this->isRequired ? '*' : '' ) : '';
$admin_buttons = $this->get_admin_buttons();
$target_input_id = $this->get_first_input_id( $form );
$for_attribute = empty( $target_input_id ) ? '' : "for='{$target_input_id}'";
$description = $this->get_description( $this->description, 'gfield_description' );
if ( $this->is_description_above( $form ) ) {
$clear = $is_admin ? "<div class='gf_clear'></div>" : '';
$field_content = sprintf( "%s<label class='%s' $for_attribute >%s%s</label>%s{FIELD}%s$clear", $admin_buttons, esc_attr( $this->get_field_label_class() ), esc_html( $field_label ), $required_div, $description, $validation_message );
} else {
$field_content = sprintf( "%s<label class='%s' $for_attribute >%s%s</label>{FIELD}%s%s", $admin_buttons, esc_attr( $this->get_field_label_class() ), esc_html( $field_label ), $required_div, $description, $validation_message );
}
return $field_content;
}
public function get_field_label_class() {
return 'gfield_label';
}
// # SUBMISSION -----------------------------------------------------------------------------------------------------
/**
* Whether this field expects an array during submission.
*
* @since 2.4
*
* @return bool
*/
public function is_value_submission_array() {
return false;
}
/**
* Used to determine the required validation result.
*
* @param int $form_id The ID of the form currently being processed.
*
* @return bool
*/
public function is_value_submission_empty( $form_id ) {
$copy_values_option_activated = $this->enableCopyValuesOption && rgpost( 'input_' . $this->id . '_copy_values_activated' );
if ( is_array( $this->inputs ) ) {
foreach ( $this->inputs as $input ) {
if ( $copy_values_option_activated ) {
$input_id = $input['id'];
$input_name = 'input_' . str_replace( '.', '_', $input_id );
$source_field_id = $this->copyValuesOptionField;
$source_input_name = str_replace( 'input_' . $this->id, 'input_' . $source_field_id, $input_name );
$value = rgpost( $source_input_name );
} else {
$value = rgpost( 'input_' . str_replace( '.', '_', $input['id'] ) );
}
if ( is_array( $value ) && ! empty( $value ) ) {
return false;
}
if ( ! is_array( $value ) && strlen( trim( $value ) ) > 0 ) {
return false;
}
}
return true;
} else {
if ( $copy_values_option_activated ) {
$value = rgpost( 'input_' . $this->copyValuesOptionField );
} else {
$value = rgpost( 'input_' . $this->id );
}
if ( is_array( $value ) ) {
//empty if any of the inputs are empty (for inputs with the same name)
foreach ( $value as $input ) {
$input = GFCommon::trim_deep( $input );
if ( GFCommon::safe_strlen( $input ) <= 0 ) {
return true;
}
}
return false;
} elseif ( $this->enablePrice ) {
list( $label, $price ) = rgexplode( '|', $value, 2 );
$is_empty = ( strlen( trim( $price ) ) <= 0 );
return $is_empty;
} else {
$is_empty = ( strlen( trim( $value ) ) <= 0 ) || ( $this->type == 'post_category' && $value < 0 );
return $is_empty;
}
}
}
/**
* Is the given value considered empty for this field.
*
* @since 2.4
*
* @param $value
*
* @return bool
*/
public function is_value_empty( $value ) {
if ( is_array( $this->inputs ) ) {
if ( $this->is_value_submission_array() ) {
foreach ( $this->inputs as $i => $input ) {
$v = isset( $value[ $i ] ) ? $value[ $i ] : '';
if ( is_array( $v ) && ! empty( $v ) ) {
return false;
}
if ( ! is_array( $v ) && strlen( trim( $v ) ) > 0 ) {
return false;
}
}
} else {
foreach ( $this->inputs as $input ) {
$input_id = (string) $input['id'];
$v = isset( $value[ $input_id ] ) ? $value[ $input_id ] : '';
if ( is_array( $v ) && ! empty( $v ) ) {
return false;
}
if ( ! is_array( $v ) && strlen( trim( $v ) ) > 0 ) {
return false;
}
}
}
} elseif ( is_array( $value ) ) {
// empty if any of the inputs are empty (for inputs with the same name)
foreach ( $value as $input ) {
$input = GFCommon::trim_deep( $input );
if ( GFCommon::safe_strlen( $input ) <= 0 ) {
return true;
}
}
return false;
} elseif ( empty( $value ) ) {
return true;
} else {
return false;
}
return true;
}
/**
* Override this method to perform custom validation logic.
*
* Return the result (bool) by setting $this->failed_validation.
* Return the validation message (string) by setting $this->validation_message.
*
* @param string|array $value The field value from get_value_submission().
* @param array $form The Form Object currently being processed.
*/
public function validate( $value, $form ) {
//
}
/**
* Retrieve the field value on submission.
*
* @param array $field_values The dynamic population parameter names with their corresponding values to be populated.
* @param bool|true $get_from_post_global_var Whether to get the value from the $_POST array as opposed to $field_values.
*
* @return array|string
*/
public function get_value_submission( $field_values, $get_from_post_global_var = true ) {
$inputs = $this->get_entry_inputs();
if ( is_array( $inputs ) ) {
$value = array();
foreach ( $inputs as $input ) {
$value[ strval( $input['id'] ) ] = $this->get_input_value_submission( 'input_' . str_replace( '.', '_', strval( $input['id'] ) ), RGForms::get( 'name', $input ), $field_values, $get_from_post_global_var );
}
} else {
$value = $this->get_input_value_submission( 'input_' . $this->id, $this->inputName, $field_values, $get_from_post_global_var );
}
return $value;
}
/**
* Retrieve the input value on submission.
*
* @param string $standard_name The input name used when accessing the $_POST.
* @param string $custom_name The dynamic population parameter name.
* @param array $field_values The dynamic population parameter names with their corresponding values to be populated.
* @param bool|true $get_from_post_global_var Whether to get the value from the $_POST array as opposed to $field_values.
*
* @return array|string
*/
public function get_input_value_submission( $standard_name, $custom_name = '', $field_values = array(), $get_from_post_global_var = true ) {
$form_id = $this->formId;
if ( ! empty( $_POST[ 'is_submit_' . $form_id ] ) && $get_from_post_global_var ) {
$value = rgpost( $standard_name );
$value = GFFormsModel::maybe_trim_input( $value, $form_id, $this );
return $value;
} elseif ( $this->allowsPrepopulate ) {
return GFFormsModel::get_parameter_value( $custom_name, $field_values, $this );
}
}
// # ENTRY RELATED --------------------------------------------------------------------------------------------------
/**
* Override and return null if a multi-input field value is to be stored under the field ID instead of the individual input IDs.
*
* @return array|null
*/
public function get_entry_inputs() {
return $this->inputs;
}
/**
* Sanitize and format the value before it is saved to the Entry Object.
*
* @param string $value The value to be saved.
* @param array $form The Form Object currently being processed.
* @param string $input_name The input name used when accessing the $_POST.
* @param int $lead_id The ID of the Entry currently being processed.
* @param array $lead The Entry Object currently being processed.
*
* @return array|string The safe value.
*/
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
if ( rgblank( $value ) ) {
return '';
} elseif ( is_array( $value ) ) {
foreach ( $value as &$v ) {
if ( is_array( $v ) ) {
$v = '';
}
$v = $this->sanitize_entry_value( $v, $form['id'] );
}
return implode( ',', $value );
} else {
return $this->sanitize_entry_value( $value, $form['id'] );
}
}
/**
* Format the entry value for when the field/input merge tag is processed. Not called for the {all_fields} merge tag.
*
* Return a value that is safe for the context specified by $format.
*
* @since Unknown
* @access public
*
* @param string|array $value The field value. Depending on the location the merge tag is being used the following functions may have already been applied to the value: esc_html, nl2br, and urlencode.
* @param string $input_id The field or input ID from the merge tag currently being processed.
* @param array $entry The Entry Object currently being processed.
* @param array $form The Form Object currently being processed.
* @param string $modifier The merge tag modifier. e.g. value
* @param string|array $raw_value The raw field value from before any formatting was applied to $value.
* @param bool $url_encode Indicates if the urlencode function may have been applied to the $value.
* @param bool $esc_html Indicates if the esc_html function may have been applied to the $value.
* @param string $format The format requested for the location the merge is being used. Possible values: html, text or url.
* @param bool $nl2br Indicates if the nl2br function may have been applied to the $value.
*
* @return string
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
if ( $format === 'html' ) {
$form_id = isset( $form['id'] ) ? absint( $form['id'] ) : null;
$allowable_tags = $this->get_allowable_tags( $form_id );
if ( $allowable_tags === false ) {
// The value is unsafe so encode the value.
if ( is_array( $value ) ) {
foreach ( $value as &$v ) {
$v = esc_html( $v );
}
$return = $value;
} else {
$return = esc_html( $value );
}
} else {
// The value contains HTML but the value was sanitized before saving.
if ( is_array( $raw_value ) ) {
$return = rgar( $raw_value, $input_id );
} else {
$return = $raw_value;
}
}
if ( $nl2br ) {
if ( is_array( $return ) ) {
foreach ( $return as &$r ) {
$r = nl2br( $r );
}
} else {
$return = nl2br( $return );
}
}
} else {
$return = $value;
}
return $return;
}
/**
* Format the entry value for display on the entries list page.
*
* Return a value that's safe to display on the page.
*
* @param string|array $value The field value.
* @param array $entry The Entry Object currently being processed.
* @param string $field_id The field or input ID currently being processed.
* @param array $columns The properties for the columns being displayed on the entry list page.
* @param array $form The Form Object currently being processed.
*
* @return string
*/
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
$allowable_tags = $this->get_allowable_tags( $form['id'] );
if ( $allowable_tags === false ) {
// The value is unsafe so encode the value.
$return = esc_html( $value );
} else {
// The value contains HTML but the value was sanitized before saving.
$return = $value;
}
return $return;
}
/**
* Format the entry value for display on the entry detail page and for the {all_fields} merge tag.
*
* Return a value that's safe to display for the context of the given $format.
*
* @param string|array $value The field value.
* @param string $currency The entry currency code.
* @param bool|false $use_text When processing choice based fields should the choice text be returned instead of the value.
* @param string $format The format requested for the location the merge is being used. Possible values: html, text or url.
* @param string $media The location where the value will be displayed. Possible values: screen or email.
*
* @return string
*/
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( is_array( $value ) ) {
_doing_it_wrong( __METHOD__, 'Override this method to handle array values', '2.0' );
return $value;
}
if ( $format === 'html' ) {
$value = nl2br( $value );
$allowable_tags = $this->get_allowable_tags();
if ( $allowable_tags === false ) {
// The value is unsafe so encode the value.
$return = esc_html( $value );
} else {
// The value contains HTML but the value was sanitized before saving.
$return = $value;
}
} else {
$return = $value;
}
return $return;
}
/**
* Format the entry value before it is used in entry exports and by framework add-ons using GFAddOn::get_field_value().
*
* For CSV export return a string or array.
*
* @param array $entry The entry currently being processed.
* @param string $input_id The field or input ID.
* @param bool|false $use_text When processing choice based fields should the choice text be returned instead of the value.
* @param bool|false $is_csv Is the value going to be used in the .csv entries export?
*
* @return string|array
*/
public function get_value_export( $entry, $input_id = '', $use_text = false, $is_csv = false ) {
if ( empty( $input_id ) ) {
$input_id = $this->id;
}
return rgar( $entry, $input_id );
}
/**
* Apply the gform_get_input_value filter to an entry's value.
*
* @since 2.4.24
*
* @param mixed $value The field or input value to be filtered.
* @param array $entry The entry currently being processed.
* @param string $input_id The ID of the input being processed from a multi-input field type or an empty string.
*
* @return mixed
*/
public function filter_input_value( $value, $entry, $input_id = '' ) {
/**
* Allows the field or input value to be overridden when populating the entry (usually on retrieval from the database).
*
* @since 1.5.3
* @since 1.9.14 Added the form and field specific versions.
*
* @param mixed $value The field or input value to be filtered.
* @param array $entry The entry currently being processed.
* @param GF_Field $this The field currently being processed.
* @param string $input_id The ID of the input being processed from a multi-input field type or an empty string.
*/
return gf_apply_filters(
array(
'gform_get_input_value',
$this->formId,
$this->id,
),
$value,
$entry,
$this,
$input_id
);
}
// # INPUT ATTRIBUTE HELPERS ----------------------------------------------------------------------------------------
/**
* Maybe return the input attribute which will trigger evaluation of conditional logic rules which depend on this field.
*
* @since 2.4
*
* @param string $event The event attribute which should be returned. Possible values: keyup, click, or change.
*
* @deprecated 2.4 Conditional Logic is now triggered based on .gfield class name. No need to hardcode calls to gf_apply_rules() to every field.
*
* @return string
*/
public function get_conditional_logic_event( $event ) {
_deprecated_function( __CLASS__ . ':' . __METHOD__, '2.4' );
if ( empty( $this->conditionalLogicFields ) || $this->is_entry_detail() || $this->is_form_editor() ) {
return '';
}
switch ( $event ) {
case 'keyup' :
return "onchange='gf_apply_rules(" . $this->formId . ',' . GFCommon::json_encode( $this->conditionalLogicFields ) . ");' onkeyup='clearTimeout(__gf_timeout_handle); __gf_timeout_handle = setTimeout(\"gf_apply_rules(" . $this->formId . ',' . GFCommon::json_encode( $this->conditionalLogicFields ) . ")\", 300);'";
break;
case 'click' :
return "onclick='gf_apply_rules(" . $this->formId . ',' . GFCommon::json_encode( $this->conditionalLogicFields ) . ");' onkeypress='gf_apply_rules(" . $this->formId . ',' . GFCommon::json_encode( $this->conditionalLogicFields ) . ");'";
break;
case 'change' :
return "onchange='gf_apply_rules(" . $this->formId . ',' . GFCommon::json_encode( $this->conditionalLogicFields ) . ");'";
break;
}
}
/**
* Maybe return the tabindex attribute.
*
* @return string
*/
public function get_tabindex() {
return GFCommon::$tab_index > 0 ? "tabindex='" . GFCommon::$tab_index ++ . "'" : '';
}
/**
* If the field placeholder property has a value return the input placeholder attribute.
*
* @return string
*/
public function get_field_placeholder_attribute() {
$placeholder_value = GFCommon::replace_variables_prepopulate( $this->placeholder );
return ! rgblank( $placeholder_value ) ? sprintf( "placeholder='%s'", esc_attr( $placeholder_value ) ) : '';
}
/**
* If the input placeholder property has a value return the input placeholder attribute.
*
* @param array $input The input currently being processed.
*
* @return string
*/
public function get_input_placeholder_attribute( $input ) {
$placeholder_value = $this->get_input_placeholder_value( $input );
return ! rgblank( $placeholder_value ) ? sprintf( "placeholder='%s'", esc_attr( $placeholder_value ) ) : '';
}
/**
* If configured retrieve the input placeholder value.
*
* @param array $input The input currently being processed.
*
* @return string
*/
public function get_input_placeholder_value( $input ) {
$placeholder = rgar( $input, 'placeholder' );
return rgblank( $placeholder ) ? '' : GFCommon::replace_variables_prepopulate( $placeholder );
}
// # BOOLEAN HELPERS ------------------------------------------------------------------------------------------------
/**
* Determine if the current location is the form editor.
*
* @return bool
*/
public function is_form_editor() {
return GFCommon::is_form_editor();
}
/**
* Determine if the current location is the entry detail page.
*
* @return bool
*/
public function is_entry_detail() {
return isset( $this->_is_entry_detail ) ? (bool) $this->_is_entry_detail : GFCommon::is_entry_detail();
}
/**
* Determine if the current location is the edit entry page.
*
* @return bool
*/
public function is_entry_detail_edit() {
return GFCommon::is_entry_detail_edit();
}
/**
* Is this a calculated product field or a number field with a calculation enabled and formula configured.
*
* @return bool
*/
public function has_calculation() {
$type = $this->get_input_type();
if ( $type == 'number' ) {
return $this->enableCalculation && $this->calculationFormula;
}
return $type == 'calculation';
}
/**
* Determines if the field description should be positioned above or below the input.
*
* @param array $form The Form Object currently being processed.
*
* @return bool
*/
public function is_description_above( $form ) {
$form_label_placement = rgar( $form, 'labelPlacement' );
$field_label_placement = $this->labelPlacement;
$form_description_placement = rgar( $form, 'descriptionPlacement' );
$field_description_placement = $this->descriptionPlacement;
if ( empty( $field_description_placement ) ) {
$field_description_placement = $form_description_placement;
}
$is_description_above = $field_description_placement == 'above' && ( $field_label_placement == 'top_label' || $field_label_placement == 'hidden_label' || ( empty( $field_label_placement ) && $form_label_placement == 'top_label' ) );
return $is_description_above;
}
public function is_administrative() {
return $this->visibility == 'administrative';
}
// # OTHER HELPERS --------------------------------------------------------------------------------------------------
/**
* Store the modifiers so they can be accessed in get_value_entry_detail() when preparing the content for the {all_fields} output.
*
* @param array $modifiers An array of modifiers to be stored.
*/
public function set_modifiers( $modifiers ) {
$this->_merge_tag_modifiers = $modifiers;
}
/**
* Retrieve the merge tag modifiers.
*
* @return array
*/
public function get_modifiers() {
return $this->_merge_tag_modifiers;
}
/**
* Retrieves the field input type.
*
* @return string
*/
public function get_input_type() {
return empty( $this->inputType ) ? $this->type : $this->inputType;
}
/**
* Adds the field button to the specified group.
*
* @param array $field_groups
*
* @return array
*/
public function add_button( $field_groups ) {
// Check a button for the type hasn't already been added
foreach ( $field_groups as $group ) {
foreach ( $group['fields'] as $button ) {
if ( isset( $button['data-type'] ) && $button['data-type'] == $this->type ) {
return $field_groups;
}
}
}
$new_button = $this->get_form_editor_button();
if ( ! empty( $new_button ) ) {
foreach ( $field_groups as &$group ) {
if ( $group['name'] == $new_button['group'] ) {
$group['fields'][] = array(
'class' => 'button',
'value' => $new_button['text'],
'data-type' => $this->type,
'onclick' => "StartAddField('{$this->type}');",
'onkeypress' => "StartAddField('{$this->type}');",
);
break;
}
}
}
return $field_groups;
}
/**
* Returns the field admin buttons for display in the form editor.
*
* @return string
*/
public function get_admin_buttons() {
$duplicate_disabled = array(
'captcha',
'post_title',
'post_content',
'post_excerpt',
'total',
'shipping',
'creditcard'
);
$duplicate_field_link = ! in_array( $this->type, $duplicate_disabled ) ? "<a class='field_duplicate_icon' id='gfield_duplicate_{$this->id}' title='" . esc_attr__( 'click to duplicate this field', 'gravityforms' ) . "' href='#' onclick='StartDuplicateField(this); return false;' onkeypress='StartDuplicateField(this); return false;'><i class='fa fa-files-o fa-lg'></i></a>" : '';
/**
* This filter allows for modification of the form field duplicate link. This will change the link for all fields
*
* @param string $duplicate_field_link The Duplicate Field Link (in HTML)
*/
$duplicate_field_link = apply_filters( 'gform_duplicate_field_link', $duplicate_field_link );
$delete_field_link = "<a class='field_delete_icon' id='gfield_delete_{$this->id}' title='" . esc_attr__( 'click to delete this field', 'gravityforms' ) . "' href='#' onclick='DeleteField(this); return false;' onkeypress='DeleteField(this); return false;'><i class='fa fa-times fa-lg'></i></a>";
/**
* This filter allows for modification of a form field delete link. This will change the link for all fields
*
* @param string $delete_field_link The Delete Field Link (in HTML)
*/
$delete_field_link = apply_filters( 'gform_delete_field_link', $delete_field_link );
$field_type_title = esc_html( GFCommon::get_field_type_title( $this->type ) );
$is_form_editor = $this->is_form_editor();
$is_entry_detail = $this->is_entry_detail();
$is_admin = $is_form_editor || $is_entry_detail;
$admin_buttons = $is_admin ? "<div class='gfield_admin_icons'><div class='gfield_admin_header_title'>{$field_type_title} : " . esc_html__( 'Field ID', 'gravityforms' ) . " {$this->id}</div>" . $delete_field_link . $duplicate_field_link . "<a href='javascript:void(0);' class='field_edit_icon edit_icon_collapsed' aria-expanded='false' title='" . esc_attr__( 'click to expand and edit the options for this field', 'gravityforms' ) . "'><i class='fa fa-caret-down fa-lg'></i></a></div>" : '';
return $admin_buttons;
}
/**
* Retrieve the field label.
*
* @param bool $force_frontend_label Should the frontend label be displayed in the admin even if an admin label is configured.
* @param string $value The field value. From default/dynamic population, $_POST, or a resumed incomplete submission.
*
* @return string
*/
public function get_field_label( $force_frontend_label, $value ) {
$field_label = $force_frontend_label ? $this->label : GFCommon::get_label( $this );
if ( ( $this->inputType == 'singleproduct' || $this->inputType == 'calculation' ) && ! rgempty( $this->id . '.1', $value ) ) {
$field_label = rgar( $value, $this->id . '.1' );
}
return $field_label;
}
/**
* Returns the input ID to be assigned to the field label for attribute.
*
* @param array $form The Form Object currently being processed.
*
* @return string
*/
public function get_first_input_id( $form ) {
$form_id = (int) rgar( $form, 'id' );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? 'input_' : "input_{$form_id}_";
if ( is_array( $this->inputs ) ) {
foreach ( $this->inputs as $input ) {
// Validate if input id is in x.x format.
if ( ! is_numeric( $input['id'] ) ) {
break;
}
if ( ! isset( $input['isHidden'] ) || ! $input['isHidden'] ) {
$field_id .= str_replace( '.', '_', $input['id'] );
break;
}
}
} else {
$field_id .= $this->id;
}
// The value is used as an HTML attribute, escape it.
return esc_attr( $field_id );
}
/**
* Returns the markup for the field description.
*
* @param string $description The field description.
* @param string $css_class The css class to be assigned to the description container.
*
* @return string
*/
public function get_description( $description, $css_class ) {
$is_form_editor = $this->is_form_editor();
$is_entry_detail = $this->is_entry_detail();
$is_admin = $is_form_editor || $is_entry_detail;
$id = "gfield_description_{$this->formId}_{$this->id}";
return $is_admin || ! empty( $description ) ? "<div class='$css_class' id='$id'>" . $description . '</div>' : '';
}
/**
* If a field has a description, the aria-describedby attribute for the input field is returned.
*
* @return string
*/
public function get_aria_describedby() {
if ( empty( $this->description ) ) {
return '';
}
$id = "gfield_description_{$this->formId}_{$this->id}";
return 'aria-describedby="' . $id . '"';
}
/**
* Returns the field default value if the field does not already have a value.
*
* @param array|string $value The field value.
*
* @return array|string
*/
public function get_value_default_if_empty( $value ) {
if ( is_array( $this->inputs ) && is_array( $value ) ) {
$defaults = $this->get_value_default();
foreach( $value as $index => &$input_value ) {
if ( rgblank( $input_value ) ) {
$input_value = rgar( $defaults, $index );
}
}
}
if ( ! GFCommon::is_empty_array( $value ) ) {
return $value;
}
return $this->get_value_default();
}
/**
* Retrieve the field default value.
*
* @return array|string
*/
public function get_value_default() {
if ( is_array( $this->inputs ) ) {
$value = array();
foreach ( $this->inputs as $input ) {
$value[ strval( $input['id'] ) ] = $this->is_form_editor() ? rgar( $input, 'defaultValue' ) : GFCommon::replace_variables_prepopulate( rgar( $input, 'defaultValue' ) );
}
} else {
$value = $this->is_form_editor() ? $this->defaultValue : GFCommon::replace_variables_prepopulate( $this->defaultValue );
}
return $value;
}
/**
* Registers the script returned by get_form_inline_script_on_page_render() for display on the front-end.
*
* @param array $form The Form Object currently being processed.
*/
public function register_form_init_scripts( $form ) {
GFFormDisplay::add_init_script( $form['id'], $this->type . '_' . $this->id, GFFormDisplay::ON_PAGE_RENDER, $this->get_form_inline_script_on_page_render( $form ) );
}
// # SANITIZATION ---------------------------------------------------------------------------------------------------
/**
* Strip unsafe tags from the field value.
*
* @param string $string The field value to be processed.
*
* @return string
*/
public function strip_script_tag( $string ) {
$allowable_tags = '<a><abbr><acronym><address><area><area /><b><base><base /><bdo><big><blockquote><body><br><br /><button><caption><cite><code><col><col /><colgroup><command><command /><dd><del><dfn><div><dl><DOCTYPE><dt><em><fieldset><form><h1><h2><h3><h4><h5><h6><head><html><hr><hr /><i><img><img /><input><input /><ins><kbd><label><legend><li><link><map><meta><meta /><noscript><ol><optgroup><option><p><param><param /><pre><q><samp><select><small><span><strong><style><sub><sup><table><tbody><td><textarea><tfoot><th><thead><title><tr><tt><ul><var><wbr><wbr />';
$string = strip_tags( $string, $allowable_tags );
return $string;
}
/**
* Override this if the field should allow html tags to be saved with the entry value. Default is false.
*
* @return bool
*/
public function allow_html() {
return false;
}
/**
* Fields should override this method to implement the appropriate sanitization specific to the field type before the value is saved.
*
* This base method will only strip HTML tags if the field or the gform_allowable_tags filter allows HTML.
*
* @param string $value The field value to be processed.
* @param int $form_id The ID of the form currently being processed.
*
* @return string
*/
public function sanitize_entry_value( $value, $form_id ) {
if ( is_array( $value ) ) {
return '';
}
$allowable_tags = $this->get_allowable_tags( $form_id );
if ( $allowable_tags === true ) {
// HTML is expected. Output will not be encoded so the value will stripped of scripts and some tags and encoded.
$return = wp_kses_post( $value );
} elseif ( $allowable_tags === false ) {
// HTML is not expected. Output will be encoded.
$return = $value;
} else {
// Some HTML is expected. Output will not be encoded so the value will stripped of scripts and some tags and encoded.
$value = wp_kses_post( $value );
// Strip all tags except those allowed by the gform_allowable_tags filter.
$return = strip_tags( $value, $allowable_tags );
}
return $return;
}
/**
* Forces settings into expected values while saving the form object.
*
* No escaping should be done at this stage to prevent double escaping on output.
*
* Currently called only for forms created after version 1.9.6.10.
*
*/
public function sanitize_settings() {
$this->id = absint( $this->id );
$this->type = wp_strip_all_tags( $this->type );
$this->formId = absint( $this->formId );
$this->label = $this->maybe_wp_kses( $this->label );
$this->adminLabel = $this->maybe_wp_kses( $this->adminLabel );
$this->description = $this->maybe_wp_kses( $this->description );
$this->isRequired = (bool) $this->isRequired;
$this->allowsPrepopulate = (bool) $this->allowsPrepopulate;
$this->inputMask = (bool) $this->inputMask;
$this->inputMaskValue = wp_strip_all_tags( $this->inputMaskValue );
if ( $this->inputMaskIsCustom !== '' ) {
$this->inputMaskIsCustom = (bool) $this->inputMaskIsCustom;
}
if ( $this->maxLength ) {
$this->maxLength = absint( $this->maxLength );
}
if ( $this->inputType ) {
$this->inputType = wp_strip_all_tags( $this->inputType );
}
if ( $this->size ) {
$this->size = GFCommon::whitelist( $this->size, $this->get_size_choices( true ) );
}
if ( $this->errorMessage ) {
$this->errorMessage = sanitize_text_field( $this->errorMessage );
}
if ( $this->labelPlacement ) {
$this->labelPlacement = wp_strip_all_tags( $this->labelPlacement );
}
if ( $this->descriptionPlacement ) {
$this->descriptionPlacement = wp_strip_all_tags( $this->descriptionPlacement );
}
if ( $this->subLabelPlacement ) {
$this->subLabelPlacement = wp_strip_all_tags( $this->subLabelPlacement );
}
if ( $this->placeholder ) {
$this->placeholder = sanitize_text_field( $this->placeholder );
}
if ( $this->cssClass ) {
$this->cssClass = wp_strip_all_tags( $this->cssClass );
}
if ( $this->inputName ) {
$this->inputName = wp_strip_all_tags( $this->inputName );
}
$this->visibility = wp_strip_all_tags( $this->visibility );
$this->noDuplicates = (bool) $this->noDuplicates;
if ( $this->defaultValue ) {
$this->defaultValue = $this->maybe_wp_kses( $this->defaultValue );
}
if ( is_array( $this->inputs ) ) {
foreach ( $this->inputs as &$input ) {
if ( isset( $input['id'] ) ) {
$input['id'] = wp_strip_all_tags( $input['id'] );
}
if ( isset( $input['customLabel'] ) ) {
$input['customLabel'] = $this->maybe_wp_kses( $input['customLabel'] );
}
if ( isset( $input['label'] ) ) {
$input['label'] = $this->maybe_wp_kses( $input['label'] );
}
if ( isset( $input['name'] ) ) {
$input['name'] = wp_strip_all_tags( $input['name'] );
}
if ( isset( $input['placeholder'] ) ) {
$input['placeholder'] = sanitize_text_field( $input['placeholder'] );
}
if ( isset( $input['defaultValue'] ) ) {
$input['defaultValue'] = wp_strip_all_tags( $input['defaultValue'] );
}
}
}
$this->sanitize_settings_choices();
$this->sanitize_settings_conditional_logic();
}
/**
* Sanitize the field choices property.
*
* @param array|null $choices The field choices property.
*
* @return array|null
*/
public function sanitize_settings_choices( $choices = null ) {
if ( is_null( $choices ) ) {
$choices = &$this->choices;
}
if ( ! is_array( $choices ) ) {
return $choices;
}
foreach ( $choices as &$choice ) {
if ( isset( $choice['isSelected'] ) ) {
$choice['isSelected'] = (bool) $choice['isSelected'];
}
if ( isset( $choice['price'] ) && ! empty( $choice['price'] ) ) {
$price_number = GFCommon::to_number( $choice['price'] );
$choice['price'] = GFCommon::to_money( $price_number );
}
if ( isset( $choice['text'] ) ) {
$choice['text'] = $this->maybe_wp_kses( $choice['text'] );
}
if ( isset( $choice['value'] ) ) {
// Strip scripts but don't encode
$allowed_protocols = wp_allowed_protocols();
$choice['value'] = wp_kses_no_null( $choice['value'], array( 'slash_zero' => 'keep' ) );
$choice['value'] = wp_kses_hook( $choice['value'], 'post', $allowed_protocols );
$choice['value'] = wp_kses_split( $choice['value'], 'post', $allowed_protocols );
}
}
return $choices;
}
/**
* Sanitize the field conditional logic object.
*
* @param array|null $logic The field conditional logic object.
*
* @return array|null
*/
public function sanitize_settings_conditional_logic( $logic = null ) {
if ( is_null( $logic ) ) {
$logic = &$this->conditionalLogic;
}
$logic = GFFormsModel::sanitize_conditional_logic( $logic );
return $logic;
}
/**
* Applies wp_kses() if the current user doesn't have the unfiltered_html capability
*
* @param $html
* @param string $allowed_html
* @param array $allowed_protocols
*
* @return string
*/
public function maybe_wp_kses( $html, $allowed_html = 'post', $allowed_protocols = array() ) {
return GFCommon::maybe_wp_kses( $html, $allowed_html, $allowed_protocols );
}
/**
* Returns the allowed HTML tags for the field value.
*
* FALSE disallows HTML tags.
* TRUE allows all HTML tags allowed by wp_kses_post().
* A string of HTML tags allowed. e.g. '<p><a><strong><em>'
*
* @param null|int $form_id If not specified the form_id field property is used.
*
* @return bool|string TRUE, FALSE or a string of tags.
*/
public function get_allowable_tags( $form_id = null ) {
if ( empty( $form_id ) ) {
$form_id = $this->form_id;
}
$form_id = absint( $form_id );
$allow_html = $this->allow_html();
/**
* Allows the list of tags allowed in the field value to be modified.
*
* Return FALSE to disallow HTML tags.
* Return TRUE to allow all HTML tags allowed by wp_kses_post().
* Return a string of HTML tags allowed. e.g. '<p><a><strong><em>'
*
* @since Unknown
*
* @param bool $allow_html
* @param GF_Field $this
* @param int $form_id
*/
$allowable_tags = apply_filters( 'gform_allowable_tags', $allow_html, $this, $form_id );
$allowable_tags = apply_filters( "gform_allowable_tags_{$form_id}", $allowable_tags, $this, $form_id );
return $allowable_tags;
}
/**
* Actions to be performed after the field has been converted to an object.
*
* @since 2.1.2.7
* @access public
*
* @uses GF_Field::failed_validation()
* @uses GF_Field::validation_message()
* @used-by GFFormsModel::convert_field_objects()
*
* @return void
*/
public function post_convert_field() {
// Fix an issue where fields can show up as invalid in the form editor if the form was updated using the form object returned after a validation failure.
unset( $this->failed_validation );
unset( $this->validation_message );
}
/**
* Returns the choices for the Field Size setting.
*
* @since 2.4.19
*
* @param bool $values_only Indicates if only the choice values should be returned.
*
* @return array
*/
public function get_size_choices( $values_only = false ) {
$choices = array(
array( 'value' => 'small', 'text' => __( 'Small', 'gravityforms' ) ),
array( 'value' => 'medium', 'text' => __( 'Medium', 'gravityforms' ) ),
array( 'value' => 'large', 'text' => __( 'Large', 'gravityforms' ) ),
);
/**
* Allows the choices for Field Size setting to be customized.
*
* @since 2.4.19
*
* @param array $choices An array of choices (value and text) to be included in the Field Size setting.
*/
$choices = apply_filters( 'gform_field_size_choices', $choices );
return $values_only ? wp_list_pluck( $choices, 'value' ) : $choices;
}
// # FIELD FILTER UI HELPERS ---------------------------------------------------------------------------------------
/**
* Returns the filter settings for the current field.
*
* If overriding to add custom settings call the parent method first to get the default settings.
*
* @since 2.4
*
* @return array
*/
public function get_filter_settings() {
$filter_settings = array(
'key' => $this->id,
'text' => GFFormsModel::get_label( $this ),
);
$sub_filters = $this->get_filter_sub_filters();
if ( ! empty( $sub_filters ) ) {
$filter_settings['group'] = true;
$filter_settings['filters'] = $sub_filters;
} else {
$filter_settings['preventMultiple'] = false;
$filter_settings['operators'] = $this->get_filter_operators();
$values = $this->get_filter_values();
if ( ! empty( $values ) ) {
$filter_settings['values'] = $values;
}
}
return $filter_settings;
}
/**
* Returns the filter operators for the current field.
*
* @since 2.4
*
* @return array
*/
public function get_filter_operators() {
return array( 'is', 'isnot', '>', '<' );
}
/**
* Returns the filters values setting for the current field.
*
* @since 2.4
*
* @return array
*/
public function get_filter_values() {
if ( ! is_array( $this->choices ) ) {
return array();
}
$choices = $this->choices;
if ( $this->type == 'post_category' ) {
foreach ( $choices as &$choice ) {
$choice['value'] = $choice['text'] . ':' . $choice['value'];
}
}
if ( $this->enablePrice ) {
foreach ( $choices as &$choice ) {
$price = rgempty( 'price', $choice ) ? 0 : GFCommon::to_number( rgar( $choice, 'price' ) );
$choice['value'] .= '|' . $price;
}
}
return $choices;
}
/**
* Returns the sub-filters for the current field.
*
* @since 2.4
*
* @return array
*/
public function get_filter_sub_filters() {
return array();
}
}
class-gf-field-email.php 0000666 00000032211 15126403614 0011127 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Email extends GF_Field {
public $type = 'email';
public function get_form_editor_field_title() {
return esc_attr__( 'Email', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'email_confirm_setting',
'admin_label_setting',
'size_setting',
'rules_setting',
'visibility_setting',
'duplicate_setting',
'default_value_setting',
'placeholder_setting',
'description_setting',
'css_class_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
public function get_entry_inputs() {
return null;
}
/**
* Whether this field expects an array during submission.
*
* @since 2.4
*
* @return bool
*/
public function is_value_submission_array() {
return (bool) $this->emailConfirmEnabled ;
}
public function validate( $value, $form ) {
$email = is_array( $value ) ? rgar( $value, 0 ) : $value; // Form objects created in 1.8 will supply a string as the value.
$is_blank = rgblank( $value ) || ( is_array( $value ) && rgempty( array_filter( $value ) ) );
if ( ! $is_blank && ! GFCommon::is_valid_email( $email ) ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'Please enter a valid email address.', 'gravityforms' ) : $this->errorMessage;
} elseif ( $this->emailConfirmEnabled && ! empty( $email ) ) {
$confirm = is_array( $value ) ? rgar( $value, 1 ) : $this->get_input_value_submission( 'input_' . $this->id . '_2' );
if ( $confirm != $email ) {
$this->failed_validation = true;
$this->validation_message = esc_html__( 'Your emails do not match.', 'gravityforms' );
}
}
}
public function get_field_input( $form, $value = '', $entry = null ) {
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
if ( is_array( $value ) ) {
$value = array_values( $value );
}
$form_id = absint( $form['id'] );
$id = absint( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$form_id = ( $is_entry_detail || $is_form_editor ) && empty( $form_id ) ? rgget( 'id' ) : $form_id;
$size = $this->size;
$disabled_text = $is_form_editor ? "disabled='disabled'" : '';
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $this->emailConfirmEnabled ? '' : $size . $class_suffix; //Size only applies when confirmation is disabled
$class = esc_attr( $class );
$form_sub_label_placement = rgar( $form, 'subLabelPlacement' );
$field_sub_label_placement = $this->subLabelPlacement;
$is_sub_label_above = $field_sub_label_placement == 'above' || ( empty( $field_sub_label_placement ) && $form_sub_label_placement == 'above' );
$sub_label_class_attribute = $field_sub_label_placement == 'hidden_label' ? "class='hidden_sub_label screen-reader-text'" : '';
$html_input_type = RGFormsModel::is_html5_enabled() ? 'email' : 'text';
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$aria_describedby = $this->get_aria_describedby();
$enter_email_field_input = GFFormsModel::get_input( $this, $this->id . '' );
$confirm_field_input = GFFormsModel::get_input( $this, $this->id . '.2' );
$enter_email_label = rgar( $enter_email_field_input, 'customLabel' ) != '' ? $enter_email_field_input['customLabel'] : esc_html__( 'Enter Email', 'gravityforms' );
$enter_email_label = gf_apply_filters( array( 'gform_email', $form_id ), $enter_email_label, $form_id );
$confirm_email_label = rgar( $confirm_field_input, 'customLabel' ) != '' ? $confirm_field_input['customLabel'] : esc_html__( 'Confirm Email', 'gravityforms' );
$confirm_email_label = gf_apply_filters( array( 'gform_email_confirm', $form_id ), $confirm_email_label, $form_id );
$single_placeholder_attribute = $this->get_field_placeholder_attribute();
$enter_email_placeholder_attribute = $this->get_input_placeholder_attribute( $enter_email_field_input );
$confirm_email_placeholder_attribute = $this->get_input_placeholder_attribute( $confirm_field_input );
if ( $is_form_editor ) {
$single_style = $this->emailConfirmEnabled ? "style='display:none;'" : '';
$confirm_style = $this->emailConfirmEnabled ? '' : "style='display:none;'";
if ( $is_sub_label_above ) {
return "<div class='ginput_container ginput_container_email ginput_single_email' {$single_style}>
<input name='input_{$id}' type='{$html_input_type}' class='" . esc_attr( $class ) . "' disabled='disabled' {$single_placeholder_attribute} {$required_attribute} {$invalid_attribute} />
<div class='gf_clear gf_clear_complex'></div>
</div>
<div class='ginput_complex ginput_container ginput_container_email ginput_confirm_email' {$confirm_style} id='{$field_id}_container'>
<span id='{$field_id}_1_container' class='ginput_left'>
<label for='{$field_id}' {$sub_label_class_attribute}>{$enter_email_label}</label>
<input class='{$class}' type='text' name='input_{$id}' id='{$field_id}' disabled='disabled' {$enter_email_placeholder_attribute} {$required_attribute} {$invalid_attribute} />
</span>
<span id='{$field_id}_2_container' class='ginput_right'>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$confirm_email_label}</label>
<input class='{$class}' type='text' name='input_{$id}_2' id='{$field_id}_2' disabled='disabled' {$confirm_email_placeholder_attribute} {$required_attribute} {$invalid_attribute} />
</span>
<div class='gf_clear gf_clear_complex'></div>
</div>";
} else {
return "<div class='ginput_container ginput_container_email ginput_single_email' {$single_style}>
<input name='input_{$id}' type='{$html_input_type}' class='" . esc_attr( $class ) . "' disabled='disabled' {$single_placeholder_attribute} {$required_attribute} {$invalid_attribute} />
<div class='gf_clear gf_clear_complex'></div>
</div>
<div class='ginput_complex ginput_container ginput_container_email ginput_confirm_email' {$confirm_style} id='{$field_id}_container'>
<span id='{$field_id}_1_container' class='ginput_left'>
<input class='{$class}' type='text' name='input_{$id}' id='{$field_id}' disabled='disabled' {$enter_email_placeholder_attribute} {$required_attribute} {$invalid_attribute} />
<label for='{$field_id}' {$sub_label_class_attribute}>{$enter_email_label}</label>
</span>
<span id='{$field_id}_2_container' class='ginput_right'>
<input class='{$class}' type='text' name='input_{$id}_2' id='{$field_id}_2' disabled='disabled' {$confirm_email_placeholder_attribute} {$required_attribute} {$invalid_attribute} />
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$confirm_email_label}</label>
</span>
<div class='gf_clear gf_clear_complex'></div>
</div>";
}
} else {
if ( $this->emailConfirmEnabled && ! $is_entry_detail ) {
$first_tabindex = $this->get_tabindex();
$last_tabindex = $this->get_tabindex();
$email_value = is_array( $value ) ? rgar( $value, 0 ) : $value;
$email_value = esc_attr( $email_value );
$confirmation_value = is_array( $value ) ? rgar( $value, 1 ) : rgpost( 'input_' . $this->id . '_2' );
$confirmation_value = esc_attr( $confirmation_value );
$confirmation_disabled = $is_entry_detail ? "disabled='disabled'" : $disabled_text;
if ( $is_sub_label_above ) {
return "<div class='ginput_complex ginput_container ginput_container_email' id='{$field_id}_container'>
<span id='{$field_id}_1_container' class='ginput_left'>
<label for='{$field_id}'>" . $enter_email_label . "</label>
<input class='{$class}' type='{$html_input_type}' name='input_{$id}' id='{$field_id}' value='{$email_value}' {$first_tabindex} {$disabled_text} {$enter_email_placeholder_attribute} {$required_attribute} {$invalid_attribute}/>
</span>
<span id='{$field_id}_2_container' class='ginput_right'>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$confirm_email_label}</label>
<input class='{$class}' type='{$html_input_type}' name='input_{$id}_2' id='{$field_id}_2' value='{$confirmation_value}' {$last_tabindex} {$confirmation_disabled} {$confirm_email_placeholder_attribute} {$required_attribute} {$invalid_attribute}/>
</span>
<div class='gf_clear gf_clear_complex'></div>
</div>";
} else {
return "<div class='ginput_complex ginput_container ginput_container_email' id='{$field_id}_container'>
<span id='{$field_id}_1_container' class='ginput_left'>
<input class='{$class}' type='{$html_input_type}' name='input_{$id}' id='{$field_id}' value='{$email_value}' {$first_tabindex} {$disabled_text} {$enter_email_placeholder_attribute} {$required_attribute} {$invalid_attribute}/>
<label for='{$field_id}' {$sub_label_class_attribute}>{$enter_email_label}</label>
</span>
<span id='{$field_id}_2_container' class='ginput_right'>
<input class='{$class}' type='{$html_input_type}' name='input_{$id}_2' id='{$field_id}_2' value='{$confirmation_value}' {$last_tabindex} {$confirmation_disabled} {$confirm_email_placeholder_attribute} {$required_attribute} {$invalid_attribute}/>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$confirm_email_label}</label>
</span>
<div class='gf_clear gf_clear_complex'></div>
</div>";
}
} else {
$tabindex = $this->get_tabindex();
$value = esc_attr( $value );
$class = esc_attr( $class );
return "<div class='ginput_container ginput_container_email'>
<input name='input_{$id}' id='{$field_id}' type='{$html_input_type}' value='$value' class='{$class}' {$tabindex} {$disabled_text} {$single_placeholder_attribute} {$required_attribute} {$invalid_attribute} {$aria_describedby}/>
</div>";
}
}
}
public function get_field_label_class(){
return $this->emailConfirmEnabled ? 'gfield_label gfield_label_before_complex' : 'gfield_label';
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( GFCommon::is_valid_email( $value ) && $format == 'html' ) {
return sprintf( "<a href='mailto:%s'>%s</a>", esc_attr( $value ), esc_html( $value ) );
}
return esc_html( $value );
}
public function get_value_submission( $field_values, $get_from_post_global_var = true ) {
if ( $this->emailConfirmEnabled && ! $this->is_entry_detail() && is_array( $this->inputs ) ) {
$value[0] = $this->get_input_value_submission( 'input_' . $this->id, $this->inputName, $field_values, $get_from_post_global_var );
$value[1] = $this->get_input_value_submission( 'input_' . $this->id . '_2', $this->inputName, $field_values, $get_from_post_global_var );
} else {
$value = $this->get_input_value_submission( 'input_' . $this->id, $this->inputName, $field_values, $get_from_post_global_var );
}
return $value;
}
/**
* Removes the "for" attribute in the field label when the confirmation input is enabled.
* Inputs are only allowed one label (a11y) and the inputs already have labels.
*
* @since 2.4
* @access public
*
* @param array $form The Form Object currently being processed.
*
* @return string
*/
public function get_first_input_id( $form ) {
return $this->emailConfirmEnabled ? '' : parent::get_first_input_id( $form );
}
// # FIELD FILTER UI HELPERS ---------------------------------------------------------------------------------------
/**
* Returns the filter operators for the current field.
*
* @since 2.4
*
* @return array
*/
public function get_filter_operators() {
$operators = parent::get_filter_operators();
$operators[] = 'contains';
return $operators;
}
}
GF_Fields::register( new GF_Field_Email() );
class-gf-field-text.php 0000666 00000016253 15126403614 0011034 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Text extends GF_Field {
public $type = 'text';
public function get_form_editor_field_title() {
return esc_attr__( 'Single Line Text', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'input_mask_setting',
'maxlen_setting',
'password_field_setting',
'rules_setting',
'visibility_setting',
'duplicate_setting',
'default_value_setting',
'placeholder_setting',
'description_setting',
'css_class_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
/**
* Return the result (bool) by setting $this->failed_validation.
* Return the validation message (string) by setting $this->validation_message.
*
* @since 2.4.11
*
* @param string|array $value The field value from get_value_submission().
* @param array $form The Form Object currently being processed.
*/
public function validate( $value, $form ) {
if ( ! $this->maxLength || ! is_numeric( $this->maxLength ) ) {
return;
}
if ( GFCommon::safe_strlen( $value ) > $this->maxLength ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'The text entered exceeds the maximum number of characters.', 'gravityforms' ) : $this->errorMessage;
}
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$html_input_type = 'text';
if ( $this->enablePasswordInput && ! $is_entry_detail ) {
$html_input_type = 'password';
}
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$value = esc_attr( $value );
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$class = esc_attr( $class );
$max_length = is_numeric( $this->maxLength ) ? "maxlength='{$this->maxLength}'" : '';
$tabindex = $this->get_tabindex();
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$placeholder_attribute = $this->get_field_placeholder_attribute();
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$aria_describedby = $this->get_aria_describedby();
$input = "<input name='input_{$id}' id='{$field_id}' type='{$html_input_type}' value='{$value}' class='{$class}' {$max_length} {$aria_describedby} {$tabindex} {$placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>";
return sprintf( "<div class='ginput_container ginput_container_text'>%s</div>", $input );
}
public function allow_html() {
return in_array( $this->type, array( 'post_custom_field', 'post_tags' ) ) ? true : false;
}
/**
* Gets merge tag values.
*
* @since Unknown
* @access public
*
* @uses GF_Field::get_allowable_tags()
*
* @param array|string $value The value of the input.
* @param string $input_id The input ID to use.
* @param array $entry The Entry Object.
* @param array $form The Form Object
* @param string $modifier The modifier passed.
* @param array|string $raw_value The raw value of the input.
* @param bool $url_encode If the result should be URL encoded.
* @param bool $esc_html If the HTML should be escaped.
* @param string $format The format that the value should be.
* @param bool $nl2br If the nl2br function should be used.
*
* @return string The processed merge tag.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
if ( $format === 'html' ) {
$value = $raw_value;
if ( $nl2br ) {
$value = nl2br( $value );
}
$form_id = absint( $form['id'] );
$allowable_tags = $this->get_allowable_tags( $form_id );
if ( $allowable_tags === false ) {
// The value is unsafe so encode the value.
$return = esc_html( $value );
} else {
// The value contains HTML but the value was sanitized before saving.
$return = $value;
}
} else {
$return = $value;
}
return $return;
}
/**
* Format the entry value safe for displaying on the entry list page.
*
* @since Unknown
* @access public
*
* @uses GF_Field::get_allowable_tags()
*
* @param string $value The field value.
* @param array $entry The Entry Object currently being processed.
* @param string $field_id The field or input ID currently being processed.
* @param array $columns The properties for the columns being displayed on the entry list page.
* @param array $form The Form Object currently being processed.
*
* @return string
*/
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
if ( is_array( $value ) ) {
return '';
}
$form_id = absint( $form['id'] );
$allowable_tags = $this->get_allowable_tags( $form_id );
if ( $allowable_tags === false ) {
// The value is unsafe so encode the value.
$return = esc_html( $value );
} else {
// The value contains HTML but the value was sanitized before saving.
$return = $value;
}
return $return;
}
/**
* Format the entry value safe for displaying on the entry detail page and for the {all_fields} merge tag.
*
* @param string|array $value The field value.
* @param string $currency The entry currency code.
* @param bool|false $use_text When processing choice based fields should the choice text be returned instead of the value.
* @param string $format The format requested for the location the merge is being used. Possible values: html, text or url.
* @param string $media The location where the value will be displayed. Possible values: screen or email.
*
* @return string
*/
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( is_array( $value ) ) {
return '';
}
if ( $format === 'html' ) {
$value = nl2br( $value );
$allowable_tags = $this->get_allowable_tags();
if ( $allowable_tags === false ) {
// The value is unsafe so encode the value.
$return = esc_html( $value );
} else {
// The value contains HTML but the value was sanitized before saving.
$return = $value;
}
} else {
$return = $value;
}
return $return;
}
// # FIELD FILTER UI HELPERS ---------------------------------------------------------------------------------------
/**
* Returns the filter operators for the current field.
*
* @since 2.4
*
* @return array
*/
public function get_filter_operators() {
$operators = parent::get_filter_operators();
$operators[] = 'contains';
return $operators;
}
}
GF_Fields::register( new GF_Field_Text() );
class-gf-field-option.php 0000666 00000001217 15126403614 0011352 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Option extends GF_Field {
public $type = 'option';
function get_form_editor_field_settings() {
return array(
'product_field_setting',
'option_field_type_setting',
'conditional_logic_field_setting',
'prepopulate_field_setting',
'label_setting',
'admin_label_setting',
'label_placement_setting',
'default_value_setting',
'placeholder_setting',
'description_setting',
'css_class_setting',
);
}
public function get_form_editor_field_title() {
return esc_attr__( 'Option', 'gravityforms' );
}
}
GF_Fields::register( new GF_Field_Option() ); class-gf-field-phone.php 0000666 00000024012 15126403614 0011151 0 ustar 00 <?php
// If Gravity Forms isn't loaded, bail.
if ( ! class_exists( 'GFForms' ) ) {
die();
}
/**
* Class GF_Field_Phone
*
* Handles the behavior of Phone fields.
*
* @since Unknown
*/
class GF_Field_Phone extends GF_Field {
/**
* Defines the field type.
*
* @since Unknown
* @access public
*
* @var string The field type.
*/
public $type = 'phone';
/**
* Defines the field title to be used in the form editor.
*
* @since Unknown
* @access public
*
* @used-by GFCommon::get_field_type_title()
*
* @return string The field title. Translatable and escaped.
*/
public function get_form_editor_field_title() {
return esc_attr__( 'Phone', 'gravityforms' );
}
/**
* Defines the field settings available within the field editor.
*
* @since Unknown
* @access public
*
* @return array The field settings available for the field.
*/
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'rules_setting',
'visibility_setting',
'duplicate_setting',
'default_value_setting',
'placeholder_setting',
'description_setting',
'phone_format_setting',
'css_class_setting',
);
}
/**
* Defines if conditional logic is supported in this field type.
*
* @since Unknown
* @access public
*
* @used-by GFFormDetail::inline_scripts()
* @used-by GFFormSettings::output_field_scripts()
*
* @return bool true
*/
public function is_conditional_logic_supported() {
return true;
}
/**
* Validates inputs for the Phone field.
*
* @since Unknown
* @access public
*
* @used-by GFFormDisplay::validate()
* @uses GF_Field_Phone::get_phone_format()
* @uses GF_Field_Phone::$validation_message
* @uses GF_Field_Phone::$errorMessage
*
* @param array|string $value The field value to be validated.
* @param array $form The Form Object.
*
* @return void
*/
public function validate( $value, $form ) {
$phone_format = $this->get_phone_format();
if ( rgar( $phone_format, 'regex' ) && $value !== '' && $value !== 0 && ! preg_match( $phone_format['regex'], $value ) ) {
$this->failed_validation = true;
if ( ! empty( $this->errorMessage ) ) {
$this->validation_message = $this->errorMessage;
}
}
}
/**
* Returns the field input.
*
* @since Unknown
* @access public
*
* @used-by GFCommon::get_field_input()
* @uses GF_Field::is_entry_detail()
* @uses GF_Field::is_form_editor()
* @uses GF_Field_Phone::$failed_validation
* @uses GF_Field_Phone::get_phone_format()
* @uses GFFormsModel::is_html5_enabled()
* @uses GF_Field::get_field_placeholder_attribute()
* @uses GF_Field_Phone::$isRequired
* @uses GF_Field::get_tabindex()
*
* @param array $form The Form Object.
* @param string $value The value of the input. Defaults to empty string.
* @param null|array $entry The Entry Object. Defaults to null.
*
* @return string The HTML markup for the field.
*/
public function get_field_input( $form, $value = '', $entry = null ) {
if ( is_array( $value ) ) {
$value = '';
}
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$form_id = $form['id'];
$id = intval( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$size = $this->size;
$disabled_text = $is_form_editor ? "disabled='disabled'" : '';
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$class = esc_attr( $class );
$instruction_div = '';
if ( $this->failed_validation ) {
$phone_format = $this->get_phone_format();
if ( rgar( $phone_format, 'instruction' ) ) {
$instruction_div = sprintf( "<div class='instruction validation_message'>%s %s</div>", esc_html__( 'Phone format:', 'gravityforms' ), $phone_format['instruction'] );
}
}
$html_input_type = RGFormsModel::is_html5_enabled() ? 'tel' : 'text';
$placeholder_attribute = $this->get_field_placeholder_attribute();
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$aria_describedby = $this->get_aria_describedby();
$tabindex = $this->get_tabindex();
return sprintf( "<div class='ginput_container ginput_container_phone'><input name='input_%d' id='%s' type='{$html_input_type}' value='%s' class='%s' {$tabindex} {$placeholder_attribute} {$required_attribute} {$invalid_attribute} {$aria_describedby} %s/>{$instruction_div}</div>", $id, $field_id, esc_attr( $value ), esc_attr( $class ), $disabled_text );
}
/**
* Gets the value of the submitted field.
*
* @since Unknown
* @access public
*
* @used-by GFFormsModel::get_field_value()
* @uses GF_Field::get_value_submission()
* @uses GF_Field_Phone::sanitize_entry_value()
*
* @param array $field_values The dynamic population parameter names with their corresponding values to be populated.
* @param bool $get_from_post_global_var Whether to get the value from the $_POST array as opposed to $field_values. Defaults to true.
*
* @return array|string
*/
public function get_value_submission( $field_values, $get_from_post_global_var = true ) {
$value = parent::get_value_submission( $field_values, $get_from_post_global_var );
$value = $this->sanitize_entry_value( $value, $this->formId );
return $value;
}
/**
* Sanitizes the entry value.
*
* @since Unknown
* @access public
*
* @used-by GF_Field_Phone::get_value_save_entry()
* @used-by GF_Field_Phone::get_value_submission()
*
* @param string $value The value to be sanitized.
* @param int $form_id The form ID of the submitted item.
*
* @return string The sanitized value.
*/
public function sanitize_entry_value( $value, $form_id ) {
$value = is_array( $value ) ? array_map( 'sanitize_text_field', $value ) : sanitize_text_field( $value );
return $value;
}
/**
* Gets the field value when an entry is being saved.
*
* @since Unknown
* @access public
*
* @used-by GFFormsModel::prepare_value()
* @uses GF_Field_Phone::sanitize_entry_value()
* @uses GF_Field_Phone::$phoneFormat
*
* @param string $value The input value.
* @param array $form The Form Object.
* @param string $input_name The input name.
* @param int $lead_id The Entry ID.
* @param array $lead The Entry Object.
*
* @return string The field value.
*/
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
$value = $this->sanitize_entry_value( $value, $form['id'] );
if ( $this->phoneFormat == 'standard' && preg_match( '/^\D?(\d{3})\D?\D?(\d{3})\D?(\d{4})$/', $value, $matches ) ) {
$value = sprintf( '(%s) %s-%s', $matches[1], $matches[2], $matches[3] );
}
return $value;
}
/**
* Outputs any inline scripts to be used when the page is rendered.
*
* @since Unknown
* @access public
*
* @used-by GF_Field::register_form_init_scripts()
* @uses GF_Field_Phone::get_phone_format()
*
* @param array $form The Form Object.
*
* @return string The inline scripts.
*/
public function get_form_inline_script_on_page_render( $form ) {
$script = '';
$phone_format = $this->get_phone_format();
if ( rgar( $phone_format, 'mask' ) ) {
$script = "jQuery('#input_{$form['id']}_{$this->id}').mask('{$phone_format['mask']}').bind('keypress', function(e){if(e.which == 13){jQuery(this).blur();} } );";
}
return $script;
}
/**
* Sanitizes the field settings.
*
* @since Unknown
* @access public
*
* @used-by GFFormDetail::add_field()
* @used-by GFFormsModel::sanitize_settings()
* @uses GF_Field::sanitize_settings()
* @uses GF_Field_Phone::get_phone_format()
* @uses GF_Field_Phone::$phoneFormat
*
* @return void
*/
public function sanitize_settings() {
parent::sanitize_settings();
if ( ! $this->get_phone_format() ) {
$this->phoneFormat = 'standard';
}
}
/**
* Get an array of phone formats.
*
* @since Unknown
* @access public
*
* @used-by GF_Field_Phone::get_phone_format()
*
* @param null|int $form_id The ID of the current form or null to use the value from the current fields form_id property. Defaults to null.
*
* @return array The phone formats available.
*/
public function get_phone_formats( $form_id = null ) {
if ( empty( $form_id ) ) {
$form_id = $this->formId;
}
$form_id = absint( $form_id );
$phone_formats = array(
'standard' => array(
'label' => '(###) ###-####',
'mask' => '(999) 999-9999',
'regex' => '/^\D?(\d{3})\D?\D?(\d{3})\D?(\d{4})$/',
'instruction' => '(###) ###-####',
),
'international' => array(
'label' => __( 'International', 'gravityforms' ),
'mask' => false,
'regex' => false,
'instruction' => false,
),
);
/**
* Allow custom phone formats to be defined.
*
* @since 2.0.0
*
* @param array $phone_formats The phone formats.
* @param int $form_id The ID of the current form.
*/
return gf_apply_filters( array( 'gform_phone_formats', $form_id ), $phone_formats, $form_id );
}
/**
* Get the properties for the fields selected phone format.
*
* @since Unknown
* @access public
*
* @used-by GF_Field_Phone::get_field_input()
* @used-by GF_Field_Phone::get_form_inline_script_on_page_render()
* @used-by GF_Field_Phone::sanitize_settings()
* @used-by GF_Field_Phone::validate()
* @uses GF_Field_Phone::get_phone_formats()
* @uses GF_Field_Phone::$phoneFormat
*
* @return array The phone format.
*/
public function get_phone_format() {
$phone_formats = $this->get_phone_formats();
return rgar( $phone_formats, $this->phoneFormat );
}
}
// Register the phone field with the field framework.
GF_Fields::register( new GF_Field_Phone() );
class-gf-field-website.php 0000666 00000007367 15126403614 0011520 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Website extends GF_Field {
public $type = 'website';
public function get_form_editor_field_title() {
return esc_attr__( 'Website', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'rules_setting',
'visibility_setting',
'duplicate_setting',
'default_value_setting',
'placeholder_setting',
'description_setting',
'css_class_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
public function validate( $value, $form ) {
if ( empty( $value ) || in_array( $value, array( 'http://', 'https://' ) ) ) {
$value = '';
if ( $this->isRequired ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'This field is required.', 'gravityforms' ) : $this->errorMessage;
}
}
if ( ! empty( $value ) && ! GFCommon::is_valid_url( $value ) ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'Please enter a valid Website URL (e.g. http://www.gravityforms.com).', 'gravityforms' ) : $this->errorMessage;
}
}
public function get_field_input( $form, $value = '', $entry = null ) {
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$form_id = $form['id'];
$id = intval( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$size = $this->size;
$disabled_text = $is_form_editor ? "disabled='disabled'" : '';
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$class = esc_attr( $class );
$is_html5 = RGFormsModel::is_html5_enabled();
$html_input_type = $is_html5 ? 'url' : 'text';
$placeholder_attribute = $this->get_field_placeholder_attribute();
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$aria_describedby = $this->get_aria_describedby();
$tabindex = $this->get_tabindex();
$value = esc_attr( $value );
$class = esc_attr( $class );
return "<div class='ginput_container ginput_container_website'>
<input name='input_{$id}' id='{$field_id}' type='$html_input_type' value='{$value}' class='{$class}' {$tabindex} {$aria_describedby} {$disabled_text} {$placeholder_attribute} {$required_attribute} {$invalid_attribute}/>
</div>";
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
$safe_value = esc_url( $value );
return GFCommon::is_valid_url( $value ) && $format == 'html' ? "<a href='$safe_value' target='_blank'>$safe_value</a>" : $safe_value;
}
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
if ( empty( $value ) || in_array( $value, array( 'http://', 'https://' ) ) ) {
return '';
}
$value = filter_var( $value, FILTER_VALIDATE_URL );
return $value ? $value : '';
}
// # FIELD FILTER UI HELPERS ---------------------------------------------------------------------------------------
/**
* Returns the filter operators for the current field.
*
* @since 2.4
*
* @return array
*/
public function get_filter_operators() {
$operators = parent::get_filter_operators();
$operators[] = 'contains';
return $operators;
}
}
GF_Fields::register( new GF_Field_Website() );
class-gf-field-total.php 0000666 00000006132 15126403614 0011166 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Total extends GF_Field {
public $type = 'total';
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'label_setting',
'admin_label_setting',
'label_placement_setting',
'description_setting',
'css_class_setting',
);
}
public function get_form_editor_field_title() {
return esc_attr__( 'Total', 'gravityforms' );
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
if ( $is_entry_detail ) {
return "<div class='ginput_container ginput_container_total'>
<input type='text' name='input_{$id}' value='{$value}' />
</div>";
} else {
return "<div class='ginput_container ginput_container_total'>
<span class='ginput_total ginput_total_{$form_id}' aria-live='polite'>" . GFCommon::to_money( '0' ) . "</span>
<input type='hidden' name='input_{$id}' id='{$field_id}' class='gform_hidden'/>
</div>";
}
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
return GFCommon::to_money( $value, $currency );
}
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
$lead = empty( $lead ) ? RGFormsModel::get_lead( $lead_id ) : $lead;
$value = GFCommon::get_order_total( $form, $lead );
return $value;
}
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
return GFCommon::to_money( $value, $entry['currency'] );
}
/**
* Gets merge tag values.
*
* @since Unknown
* @access public
*
* @uses GFCommon::to_number()
* @uses GFCommon::to_money()
* @uses GFCommon::format_variable_value()
*
* @param array|string $value The value of the input.
* @param string $input_id The input ID to use.
* @param array $entry The Entry Object.
* @param array $form The Form Object
* @param string $modifier The modifier passed.
* @param array|string $raw_value The raw value of the input.
* @param bool $url_encode If the result should be URL encoded.
* @param bool $esc_html If the HTML should be escaped.
* @param string $format The format that the value should be.
* @param bool $nl2br If the nl2br function should be used.
*
* @return string The processed merge tag.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
$format_numeric = in_array( 'price', $this->get_modifiers() );
$value = $format_numeric ? GFCommon::to_number( $value ) : GFCommon::to_money( $value );
return GFCommon::format_variable_value( $value, $url_encode, $esc_html, $format );
}
}
GF_Fields::register( new GF_Field_Total() ); class-gf-field-repeater.php 0000666 00000072706 15126403614 0011664 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
/**
* The Repeater field.
*
* 2.4
*
* Class GF_Field_Repeater
*/
class GF_Field_Repeater extends GF_Field {
public $type = 'repeater';
/**
* Returns the field title for the form editor.
*
* @since 2.4
*
* @return string
*/
public function get_form_editor_field_title() {
return esc_attr__( 'Repeater', 'gravityforms' );
}
/**
* Returns the field settings for the form editor.
*
* @since 2.4
*
* @return array
*/
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'rules_setting',
'visibility_setting',
'description_setting',
'css_class_setting',
);
}
public function get_form_editor_button() {
return array();
}
/**
* Used to determine the required validation result.
*
* @since 2.4
*
* @param int $form_id The ID of the form currently being processed.
*
* @return bool
*/
public function is_value_submission_empty( $form_id ) {
return false;
}
/**
* Validates each sub-field.
*
* @since 2.4
*
* @param string|array $items The field values from get_value_submission().
* @param array $form The Form Object currently being processed.
*/
public function validate( $items, $form ) {
if ( empty( $items ) ) {
return;
}
/* @var GF_Field[] $fields */
$fields = $this->fields;
foreach ( $items as $i => $item ) {
foreach ( $fields as $field ) {
$field->set_context_property( 'itemIndex', $i );
$inputs = $field->get_entry_inputs();
if ( is_array( $inputs ) ) {
$field_value = array();
$field_keys = array_keys( $item );
foreach ( $field_keys as $input_id ) {
if ( is_numeric( $input_id ) && absint( $input_id ) == absint( $field->id ) ) {
$field_value[ $input_id ] = $item[ $input_id ];
}
}
} else {
$field_value = isset( $item[ $field->id ] ) ? $item[ $field->id ] : '';
}
if ( $field->isRequired && $field->is_value_empty( $field_value ) ) {
$field->failed_validation = true;
} else {
$field->validate( $field_value, $form );
}
$custom_validation_result = gf_apply_filters( array( 'gform_field_validation', $form['id'], $field->id ), array(
'is_valid' => $field->failed_validation ? false : true,
'message' => $field->validation_message
), $field_value, $form, $field );
$this->failed_validation = rgar( $custom_validation_result, 'is_valid' ) ? false : true;
// Reset the field validation and item index.
$field->failed_validation = false;
$field->set_context_property( 'itemIndex', null );
if ( $this->failed_validation ) {
// One field has failed validation so the entire repeater fails.
return;
}
}
}
}
/**
* Retrieve the field value on submission.
*
* @since 2.4
*
* @param array $field_values The dynamic population parameter names with their corresponding values to be populated.
* @param bool|true $get_from_post_global_var Whether to get the value from the $_POST array as opposed to $field_values.
*
* @return array|string
*/
public function get_value_submission( $field_values, $get_from_post_global_var = true ) {
$submission_values = $this->get_value_submission_recursive( $field_values, $get_from_post_global_var );
$items = $this->hydrate( $submission_values );
return $items[ $this->id ];
}
/**
* Returns the submission values for the repeater.
*
* @since 2.4
*
* @param array $field_values
* @param bool $get_from_post_global_var
*
* @return array
*/
public function get_value_submission_recursive( $field_values, $get_from_post_global_var ) {
$items = array();
if ( isset( $this->fields ) && is_array( $this->fields ) ) {
foreach ( $this->fields as $sub_field ) {
/* @var GF_Field $sub_field */
if ( isset( $sub_field->fields ) && is_array( $sub_field->fields ) ) {
/* @var GF_Field_Repeater_Table $sub_field */
$field_items = $sub_field->get_value_submission_recursive( $field_values, $get_from_post_global_var );
} else {
$values = $sub_field->get_value_submission( $field_values, $get_from_post_global_var );
if ( is_array( $sub_field->get_entry_inputs() ) ) {
$prefix = '';
} else {
$prefix = $sub_field->id . '_';
}
$field_items = $this->flatten( $values, $prefix, $sub_field->is_value_submission_array() );
}
$items = array_merge( $items, $field_items );
}
} else {
$values = $this->get_value_submission( $field_values, $get_from_post_global_var );
$field_items = $this->flatten( $values, $this->id . '_', $this->is_value_submission_array() );
$items = array_merge( $items, $field_items );
}
return $items;
}
/**
* Utility to flatten array values recursively so they can be saved with the appropriate index.
*
* @since 2.4
*
* @param $array
* @param string $prefix
* @param bool $field_value_is_array
*
* @return array
*/
private function flatten( $array, $prefix = '', $field_value_is_array = false ) {
$result = array();
if ( ! is_array( $array ) ) {
return $result;
}
foreach ( $array as $key => $value ) {
if ( is_array( $value ) ) {
if ( $field_value_is_array && ! is_array( $value[0] ) ) {
$result[ $prefix . $key ] = $value;
} else {
$result = $result + $this->flatten( $value, $prefix . $key . '_' );
}
} else {
$result[ $prefix . $key ] = $value;
}
}
return $result;
}
/**
* Returns the field inner markup.
*
* @since 2.4
*
* @param array $form The Form Object currently being processed.
* @param string|array $values The field values. From default/dynamic population, $_POST, or a resumed incomplete submission.
* @param null|array $entry Null or the Entry Object currently being edited.
*
* @return string
*/
public function get_field_input( $form, $values = '', $entry = null ) {
if ( $this->is_form_editor() ) {
return sprintf( "<p>%s</p>", $this->label );
}
if ( empty( $values ) ) {
$values = array( '' );
}
$input_top = $this->get_input_top( $values );
$items = $this->get_input_items( $values, $entry );
$html = $input_top . $items . $this->get_input_bottom();
$max_items = intval( $this->maxItems );
return sprintf( "<div class='gfield_repeater_wrapper' data-max_items='{$max_items}'>%s</div>", $html );
}
/**
* Returns the markup for the top of the repeater container.
*
* This method must return the opening tag for the container and this tag must have the class 'gfield_repeater_container'
*
* @since 2.4
*
* @param $values
*
* @return string
*/
public function get_input_top( $values ) {
$html = "<fieldset class='gfield_repeater gfield_repeater_container'>\n";
$label = esc_html( $this->label );
$html .= "<legend class='gfield_label'>{$label}</legend>";
return $html;
}
/**
* Returns the markup for the items.
*
* This method must return a single HTML element with the class 'gfield_repeater_items'. This elemment must contain
* all the items as direct children and each item must have the class 'gfield_repeater_item'.
*
* @since 2.4
*
* @param $values
* @param $entry
*
* @return string
*/
public function get_input_items( $values, $entry ) {
/* @var GF_Field[] $fields */
$fields = $this->fields;
$form = GFAPI::get_form( $this->formId );
$rows = '<div class="gfield_repeater_items">';
$i = 0;
foreach ( $values as $value ) {
$row = "<div class='gfield_repeater_item'>";
foreach ( $fields as $field ) {
$field_value = $this->get_field_value( $field, $value );
$field->set_context_property( 'itemIndex', $i );
$field_input = $this->get_sub_field_input( $field, $form, $field_value, $entry, $i );
$row .= "<div class='gfield_repeater_cell'>" . $field_input . '</div>';
$field->set_context_property( 'itemIndex', null );
}
$buttons = $this->get_buttons( $values );
$row .= "<div class='gfield_repeater_buttons'>{$buttons}</div>";
$row .= '</div>';
$rows .= $row;
$i++;
}
$rows .= '</div>';
return $rows;
}
/**
* Return the markup for the bottom of the repeater. Close the tags opened in the top.
*
* @since 2.4
*
* @return string
*/
public function get_input_bottom() {
return '</fieldset>';
}
public function get_field_content( $value, $force_frontend_label, $form ) {
$is_form_editor = $this->is_form_editor();
$is_entry_detail = $this->is_entry_detail();
$is_admin = $is_form_editor || $is_entry_detail;
$admin_buttons = $this->get_admin_buttons();
$description = $this->get_description( $this->description, 'gfield_description' );
if ( $this->is_description_above( $form ) ) {
$clear = $is_admin ? "<div class='gf_clear'></div>" : '';
$field_content = sprintf( "%s%s{FIELD}$clear", $admin_buttons, $description );
} else {
$field_content = sprintf( "%s{FIELD}%s", $admin_buttons, $description );
}
return $field_content;
}
/**
* Returns the repeater buttons.
*
* @since 2.4
*
* @return string
*/
public function get_buttons( $values ) {
$is_form_editor = $this->is_form_editor();
$delete_display = count( $values ) == 1 ? 'visibility:hidden;' : '';
$add_events = $is_form_editor ? '' : "onclick='gformAddRepeaterItem(this)' onkeypress='gformAddRepeaterItem(this)'";
$delete_events = $is_form_editor ? '' : sprintf( "onclick='if(confirm(\"%s\")){gformDeleteRepeaterItem(this)};' onkeypress='gformDeleteRepeaterItem(this)'", esc_js( __( 'Are you sure you want to remove this item?', 'gravityforms' ) ) );
$disabled_icon_class = ! empty( $this->maxItems ) && count( $values ) >= intval( $this->maxItems ) ? 'gfield_icon_disabled' : '';
$add_button_text = $this->addButtonText ? $this->addButtonText : '+';
$remove_button_text = $this->removeButtonText ? $this->removeButtonText : '-' ;
$add_button_class = $this->addButtonText ? 'add_repeater_item_text' : 'add_repeater_item_plus';
$remove_button_class = $this->removeButtonText ? 'remove_repeater_item_text' : 'remove_repeater_item_minus';
$html = "<button type='button' class='add_repeater_item {$disabled_icon_class} {$add_button_class}' {$add_events}>" . $add_button_text . "</button>" .
"<button type='button' class='remove_repeater_item {$remove_button_class}' {$delete_events} style='{$delete_display}'>" . $remove_button_text . "</button>";
return $html;
}
/**
* Gets merge tag values.
*
* @since 2.4
*
* @param array|string $value The value of the input.
* @param string $input_id The input ID to use.
* @param array $entry The Entry Object.
* @param array $form The Form Object
* @param string $modifier The modifier passed.
* @param array|string $raw_value The raw value of the input.
* @param bool $url_encode If the result should be URL encoded.
* @param bool $esc_html If the HTML should be escaped.
* @param string $format The format that the value should be.
* @param bool $nl2br If the nl2br function should be used.
*
* @return string The processed merge tag.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
$use_value = in_array( 'value', $this->get_modifiers() );
$use_text = ! $use_value;
if ( $format == 'html' ) {
$media = $esc_html ? 'screen' :'email';
$merge_tag = $this->get_value_entry_detail( $raw_value, $entry['currency'], $use_text, $format, $media );
} else {
$merge_tag = $this->get_value_export_recursive( $entry, $input_id, $use_text, false, 0, ' ' );
}
return $merge_tag;
}
/**
* Format the entry value safe for displaying on the entry list page.
*
* @since 2.4
*
* @param string $value The field value.
* @param array $entry The Entry Object currently being processed.
* @param string $field_id The field or input ID currently being processed.
* @param array $columns The properties for the columns being displayed on the entry list page.
* @param array $form The Form Object currently being processed.
*
* @return string
*/
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
/* translators: %d: the number of items in value of the repeater field. */
$display_value = is_array( $value ) ? sprintf( esc_html__( 'Number of items: %d' ), count( $value ) ) : '';
return $display_value;
}
/**
* Format the entry value safe for displaying on the entry detail page and for the {all_fields} merge tag.
*
* @since 2.4
*
* @param string|array $item_values The field value.
* @param string $currency The entry currency code.
* @param bool|false $use_text When processing choice based fields should the choice text be returned instead of the value.
* @param string $format The format requested for the location the merge is being used. Possible values: html, text or url.
* @param string $media The location where the value will be displayed. Possible values: screen or email.
*
* @return string
*/
public function get_value_entry_detail( $item_values, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( $format == 'text' ) {
return $this->get_value_export_recursive( array( $this->id => $item_values ), $this->id, $use_text, false, 0, ' ' );
}
$repeater_style = $media == 'email' ? "style='padding: 5px 0 0 15px;font-size: 14px'" : '';
$label_style = $media == 'email' ? "style='color: rgba(35, 40, 45, 1.000);font-weight:600; padding-top:10px;font-size: 14px'" : '';
$sub_field_label_style = $media == 'email' ? "style='color:rgb(155, 154, 154);padding-top:8px;font-size: 14px;'" : '';
/* @var GF_Field[] $fields */
$fields = $this->fields;
$html = "<div class='gfield_repeater' {$repeater_style}>";
$repeater_label = $this->nestingLevel === 0 ? '' : $this->label;
$html .= "<div class='gfield_label' {$label_style}>{$repeater_label}</div>";
$html .= '<div class="gfield_repeater_items">';
foreach ( $item_values as $item_value ) {
$html .= '<div class="gfield_repeater_item">';
foreach ( $fields as $sub_field ) {
if ( $sub_field->fields ) {
$sub_field_value = $item_value[ $sub_field->id ];
} else {
$sub_field_value = $this->get_field_value( $sub_field, $item_value );
}
$label = $sub_field->get_field_label( true, $item_values );
$label = empty( $sub_field->fields ) ? "<div class='gfield_repeater_label' {$sub_field_label_style}>{$label}</div>" : '';
$value = $sub_field->get_value_entry_detail( $sub_field_value, $currency, $use_text, 'html', $media );
$value = "<div class='gfield_repeater_value' style='color:rgba(117, 117, 117, 1);font-size: 14px'>{$value}</div>";
$html .= '<div class="gfield_repeater_cell">' . $label . $value . '</div>';
}
$html .= '</div>';
}
$html .= '</div>';
$html .= '</div>';
return $html;
}
/**
* Returns the value for a field inside a repeater.
*
* @since 2.4
*
* @param GF_Field $field
* @param array|string $value
*
* @return array|string
*/
public function get_field_value( $field, $value ) {
if ( $field->fields ) {
$field_value = isset( $value[ $field->id ] ) ? $value[ $field->id ] : '';
} else {
$inputs = $field->get_entry_inputs();
if ( is_array( $value ) ) {
if ( is_array( $inputs ) ) {
$field_value = array();
$field_keys = array_keys( $value );
natsort( $field_keys );
foreach ( $field_keys as $input_id ) {
if ( is_numeric( $input_id ) && absint( $input_id ) == absint( $field->id ) ) {
$val = $value[ $input_id ];
$field_value[ $input_id ] = $val;
}
}
} else {
$field_value = isset( $value[ $field->id ] ) ? $value[ $field->id ] : '';
}
} else {
$field_value = '';
}
}
return $field_value;
}
/**
* Returns the input markup for a field inside a repeater.
*
* Appends the item index to the name and id attributes and validates the value.
*
* @since 2.4
*
* @param GF_Field $field
* @param array $form
* @param array $field_value
* @param array $entry
* @param int $index
*
* @return mixed
*/
public function get_sub_field_input( $field, $form, $field_value, $entry, $index ) {
$field_content = $this->get_sub_field_content( $field, $field_value, $form, $entry );
// Adjust all the name attributes in the markup
preg_match_all( "/(name='input_[^\[|']*)((\[[0-9]*\])*)'/", $field_content, $matches, PREG_SET_ORDER );
$replaced = array();
foreach ( $matches as $match ) {
if ( ! in_array( $match[0], $replaced ) ) {
$input_name = str_replace( $match[1], $match[1] . "[{$index}]", $match[0] );
$field_content = str_replace( $match[0], $input_name, $field_content );
$replaced[] = $match[0];
}
}
// Adjust all the id attributes in the markup
preg_match_all( "/(id='((input|choice)_[0-9|_]*))[0-9|-]*'/", $field_content, $matches, PREG_SET_ORDER );
$replaced = array();
foreach ( $matches as $match ) {
if ( ! in_array( $match[0], $replaced ) ) {
$input_id = str_replace( $match[1], $match[1] . "-{$index}", $match[0] ) ;
$field_content = str_replace( $match[0], $input_id, $field_content );
$replaced[] = $match[0];
}
}
// Adjust all the for attributes in the markup
preg_match_all( "/(for='(input|choice)_[^\[']*)'/", $field_content, $matches, PREG_SET_ORDER );
$replaced = array();
foreach ( $matches as $match ) {
if ( ! in_array( $match[1], $replaced ) ) {
$input_id = $match[1] . "-{$index}";
$field_content = str_replace( $match[1], $input_id, $field_content );
$replaced[] = $match[1];
}
}
$target_page = rgpost( 'gform_target_page_number_' . $this->formId );
$source_page = rgpost( 'gform_source_page_number_' . $this->formId );
$validate = $source_page == $field->pageNumber && rgpost( 'is_submit_' . $this->formId ) && ( $target_page == 0 || $target_page > $source_page );
if ( $validate ) {
$field->failed_validation = false;
if ( $field->isRequired && $field->is_value_empty( $field_value ) ) {
$field->failed_validation = true;
$field->validation_message = empty( $field->errorMessage ) ? __( 'This field is required.', 'gravityforms' ) : $field->errorMessage;
}
if ( ! $field->failed_validation ) {
$field->validate( $field_value, $form );
}
$custom_validation_result = gf_apply_filters( array( 'gform_field_validation', $form['id'], $field->id ), array(
'is_valid' => $field->failed_validation ? false : true,
'message' => $field->validation_message
), $field_value, $form, $field );
$field->failed_validation = rgar( $custom_validation_result, 'is_valid' ) ? false : true;
}
$validation_message = ( $field->failed_validation && ! empty( $field->validation_message ) ) ? sprintf( "<div class='gfield_description validation_message'>%s</div>", $field->validation_message ) : '';
return $field_content . $validation_message;
}
/**
* Returns the markup for the sub field.
*
* @since 2.4
*
* @param GF_Field $field
* @param string|array $value
* @param array $form
* @param array $entry
*
* @return string
*/
public function get_sub_field_content( $field, $value, $form, $entry ) {
$validation_status = $field->failed_validation;
if ( empty( $field->fields ) ) {
// Validation will be handled later inside GF_Field_Repeater::get_sub_field_input so temporarily set failed_validation to false.
$field->failed_validation = false;
}
if ( ! class_exists( 'GFFormDisplay' ) ) {
require_once( GFCommon::get_base_path() .'/form_display.php' );
}
$field_content = GFFormDisplay::get_field_content( $field, $value, true, $form['id'], $form );
$field->failed_validation = $validation_status;
return $field_content;
}
/**
* Builds the repeater's array of items.
*
* @since 2.4
*
* @param $entry
*
* @return mixed
*/
public function hydrate( $entry, $apply_filters = false ) {
$entry[ $this->id ] = $this->get_repeater_items( $entry, '', '', $apply_filters );
return $entry;
}
/**
* Recursively converts the repeater values from flattened values in the entry array into a multidimensional array
* of items.
*
* @since 2.4
*
* @param array $entry
* @param GF_Field_Repeater $repeater_field
* @param string $index
*
* @return array
*/
public function get_repeater_items( &$entry, $repeater_field = null, $index = '', $apply_filters = false ) {
if ( ! $repeater_field ) {
$repeater_field = $this;
}
$items = array();
// Blank items are not stored but we need to display them if a value exists with a higher index.
$max_indexes = $this->get_max_indexes( $entry, $repeater_field, $index );
$repeater_fields = array();
foreach ( $repeater_field->fields as $field ) {
if ( is_array( $field->fields ) ) {
$repeater_fields[] = $field;
continue;
}
for ( $i = 0; $i <= $max_indexes[ $field->id ]; $i ++ ) {
$inputs = $field->get_entry_inputs();
if ( is_array( $inputs ) ) {
foreach ( $inputs as $input ) {
$input_id = $input['id'];
$key = $input_id . $index . '_' . $i;
$value = isset( $entry[ $key ] ) ? $entry[ $key ] : '';
// Don't add new item if max indexes is 0 and value is empty.
if ( $field->isRequired || $max_indexes[ $field->id ] > 0 || ( $max_indexes[ $field->id ] === 0 && $value !== '' ) ) {
if ( $apply_filters ) {
$items[ $i ][ $input_id ] = $field->filter_input_value( $value, $entry );
} else {
$items[ $i ][ $input_id ] = $value;
}
}
if ( isset( $entry[ $key ] ) ) {
unset( $entry[ $key ] );
}
}
} else {
$key = $field->id . $index . '_' . $i;
$value = isset( $entry[ $key ] ) ? $entry[ $key ] : '';
if ( $field->isRequired || $max_indexes[ $field->id ] > 0 || ( $max_indexes[ $field->id ] === 0 && $value !== '' ) ) {
if ( $apply_filters ) {
$items[ $i ][ $field->id ] = $field->filter_input_value( $value, $entry );
} else {
$items[ $i ][ $field->id ] = $value;
}
}
if ( isset( $entry[ $key ] ) ) {
unset( $entry[ $key ] );
}
}
}
}
if ( ! empty( $repeater_fields ) ) {
$i = 0;
do {
$all_repeaters_have_values = true;
foreach ( $repeater_fields as $repeater ) {
$v = $this->get_repeater_items( $entry, $repeater, $index . '_' . $i );
$is_empty = $this->empty_deep( $v );
if ( ( $i == 0 || ! $is_empty ) || ( empty( $index ) && isset( $items[ $i ] ) && ! $this->empty_deep( $items[ $i ] ) ) ) {
$items[ $i ][ $repeater->id ] = $v;
}
if ( $is_empty ) {
$all_repeaters_have_values = false;
}
}
$i ++;
} while ( $all_repeaters_have_values );
}
return $items;
}
/**
* Parses all the flat entry array keys and returns the maximum index by field ID.
*
* @since 2.4
*
* @param array $entry The entry array
* @param GF_Field_Repeater $repeater_field The repeater field
* @param string $index The index prefix
*
* @return array
*/
protected function get_max_indexes( $entry, $repeater_field, $index ) {
$field_ids = array_keys( $entry );
$max_indexes = array();
$matches = array();
foreach ( $repeater_field->fields as $field ) {
if ( ! isset( $matches[ $field->id ] ) ) {
$matches[ $field->id ] = array( 0 );
}
foreach ( $field_ids as $f_id ) {
if ( preg_match( "/{$field->id}[^_]*{$index}_([0-9]+)/", $f_id, $m ) ) {
$matches[ $field->id ][] = intval( $m[1] );
}
}
$max_indexes[ $field->id ] = max( $matches[ $field->id ] );
}
return $max_indexes;
}
/**
* Recursively checks whether a multi-dimensional array is empty.
*
* @since 2.4
*
* @param $val
*
* @return bool
*/
public function empty_deep( $val ) {
$result = true;
if ( is_array( $val ) && count( $val ) > 0 ) {
foreach ( $val as $v ) {
$result = $result && $this->empty_deep( $v );
}
} else {
$result = empty( $val );
}
return $result;
}
/**
* Returns the sub-filters for the current field.
*
* @since 2.4
*
* @return array
*/
public function get_filter_sub_filters() {
$filters = array();
$fields = $this->fields;
foreach ( $fields as $field ) {
/** @var GF_Field $field */
$filter_settings = array(
'key' => $field->id,
'text' => GFFormsModel::get_label( $field, false, true ),
);
if ( is_array( $field->fields ) ) {
$filter_settings = $field->get_filter_settings();
$filters[] = $filter_settings;
continue;
}
$sub_filters = $field->get_filter_sub_filters();
if ( ! empty( $sub_filters ) ) {
$filter_settings['group'] = true;
$filter_settings['filters'] = $sub_filters;
} else {
$filter_settings['preventMultiple'] = false;
$filter_settings['operators'] = $field->get_filter_operators();
$values = $field->get_filter_values();
if ( ! empty( $values ) ) {
$filter_settings['values'] = $values;
}
}
$values = $field->get_filter_values();
if ( ! empty( $values ) ) {
$filter_settings['values'] = $values;
}
$filters[] = $filter_settings;
}
return $filters;
}
/**
* Returns the filter settings for the current field.
*
* If overriding to add custom settings call the parent method first to get the default settings.
*
* @since 2.4
*
* @return array
*/
public function get_filter_settings() {
$filter_settings = parent::get_filter_settings();
$filter_settings['isNestable'] = true;
return $filter_settings;
}
/**
* Format the entry value before it is used in entry exports and by framework add-ons using GFAddOn::get_field_value().
*
* @since 2.4
*
* @param array $entry The entry currently being processed.
* @param string $input_id The field or input ID.
* @param bool|false $use_text When processing choice based fields should the choice text be returned instead of the value.
* @param bool|false $is_csv Is the value going to be used in the .csv entries export?
*
* @return string|array
*/
public function get_value_export( $entry, $input_id = '', $use_text = false, $is_csv = false ) {
$export = $this->get_value_export_recursive( $entry, $input_id, $use_text, $is_csv );
return $export;
}
/**
* Format the entry value before it is used in entry exports and by framework add-ons using GFAddOn::get_field_value().
*
* @since 2.4
*
* @param array $entry The entry currently being processed.
* @param string $input_id The field or input ID.
* @param bool|false $use_text When processing choice based fields should the choice text be returned instead of the value.
* @param bool|false $is_csv Is the value going to be used in the .csv entries export?
*
* @return string|array
*/
public function get_value_export_recursive( $entry, $input_id = '', $use_text = false, $is_csv = false, $depth = 0, $padding = ' ' ) {
if ( empty( $input_id ) ) {
$input_id = $this->id;
}
$items = rgar( $entry, $input_id );
/* @var GF_Field[] $fields */
$fields = $this->fields;
$csv = array();
foreach ( $items as $item ) {
foreach ( $fields as $field ) {
$inputs = $field->get_entry_inputs();
if ( is_array( $inputs ) ) {
$field_value = array();
$field_keys = array_keys( $item );
foreach ( $field_keys as $input_id ) {
if ( is_numeric( $input_id ) && absint( $input_id ) == absint( $field->id ) ) {
$field_value[ $input_id ] = $item[ $input_id ];
}
}
} else {
$field_value = isset( $item[ $field->id ] ) ? $item[ $field->id ] : '';
$field_value = array( (string) $field->id => $field_value );
}
$label = str_repeat( $padding, $depth ) . GFFormsModel::get_label( $field );
if ( is_array( $field->fields ) ) {
$new_depth = $depth + 1;
$line = $label . "\n" . $field->get_value_export_recursive( $field_value, $field->id, $use_text, $is_csv, $new_depth, $padding );
if ( $depth == 0 ) {
$line .= "\n";
}
} else {
if ( 'list' === $field->get_input_type() && ! empty( $field_value[ $field->id ] ) ) {
$list_rows = maybe_unserialize( $field_value[ $field->id ] );
if ( is_array( $list_rows[0] ) ) {
$lines = array();
foreach ( $list_rows as $i => $list_row ) {
$row_label = $label . ' ' . ( $i + 1 );
// Prepare row value.
$row_value = implode( '|', $list_row );
if ( strpos( $row_value, '=' ) === 0 ) {
// Prevent Excel formulas
$row_value = "'" . $row_value;
}
$lines[] = $row_label . ': ' . $row_value;
}
$line = implode( "\n", $lines );
} else {
$value = implode( '|', $list_rows );
if ( strpos( $value, '=' ) === 0 ) {
// Prevent Excel formulas
$value = "'" . $value;
}
$line = $label . ': ' . $value;
}
} else {
$line = $label . ': ' . $field->get_value_export( $field_value, $field->id, $use_text, $is_csv );
}
}
$csv[] = $line;
}
}
return implode( "\n", $csv );
}
/**
* Store the modifiers so they can be accessed when preparing the {all_fields} and field merge tag output.
*
* @since 2.4
*
* @param array $modifiers An array of modifiers to be stored.
*/
public function set_modifiers( $modifiers ) {
parent::set_modifiers( $modifiers );
/* @var GF_Field $sub_field */
foreach ( $this->fields as $sub_field ) {
$sub_field->set_modifiers( $modifiers );
}
}
}
GF_Fields::register( new GF_Field_Repeater() );
class-gf-field-textarea.php 0000666 00000032570 15126403614 0011665 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Textarea extends GF_Field {
public $type = 'textarea';
public function get_form_editor_field_title() {
return esc_attr__( 'Paragraph Text', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'maxlen_setting',
'size_setting',
'rules_setting',
'visibility_setting',
'duplicate_setting',
'default_value_textarea_setting',
'placeholder_textarea_setting',
'description_setting',
'css_class_setting',
'rich_text_editor_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
public function allow_html() {
return empty( $this->useRichTextEditor ) ? false : true;
}
public function get_field_input( $form, $value = '', $entry = null ) {
global $current_screen;
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$is_admin = $is_entry_detail || $is_form_editor;
$id = intval( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$class = esc_attr( $class );
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$maxlength_attribute = is_numeric( $this->maxLength ) ? "maxlength='{$this->maxLength}'" : '';
$placeholder_attribute = $this->get_field_placeholder_attribute();
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$aria_describedby = $this->get_aria_describedby();
$tabindex = $this->get_tabindex();
if ( $this->get_allowable_tags() === false ) {
$value = esc_textarea( $value );
} else {
$value = wp_kses_post( $value );
}
//see if the field is set to use the rich text editor
if ( ! $is_admin && $this->is_rich_edit_enabled() && ( ! $current_screen || ( $current_screen && ! rgobj( $current_screen, 'is_block_editor' ) ) ) ) {
//placeholders cannot be used with the rte; message displayed in admin when this occurs
//field cannot be used in conditional logic by another field; message displayed in admin and field removed from conditional logic drop down
$tabindex = GFCommon::$tab_index > 0 ? GFCommon::$tab_index ++ : '';
add_filter( 'mce_buttons', array( $this, 'filter_mce_buttons' ), 10, 2 );
add_filter( 'mce_buttons_2', array( $this, 'filter_mce_buttons' ), 10, 2 );
add_filter( 'mce_buttons_3', array( $this, 'filter_mce_buttons' ), 10, 2 );
add_filter( 'mce_buttons_4', array( $this, 'filter_mce_buttons' ), 10, 2 );
/**
* Filters the field options for the rich text editor.
*
* @since 2.0.0
*
* @param array $editor_settings Array of settings that can be changed.
* @param object $this The field object
* @param array $form Current form object
* @param array $entry Current entry object, if available
*
* Additional filters for specific form and fields IDs.
*/
$editor_settings = apply_filters( 'gform_rich_text_editor_options', array(
'textarea_name' => 'input_' . $id,
'wpautop' => true,
'editor_class' => $class,
'editor_height' => rgar( array( 'small' => 110, 'medium' => 180, 'large' => 280 ), $this->size ? $this->size : 'medium' ),
'tabindex' => $tabindex,
'media_buttons' => false,
'quicktags' => false,
'tinymce' => array( 'init_instance_callback' => "function (editor) {
editor.on( 'keyup paste mouseover', function (e) {
var content = editor.getContent( { format: 'text' } ).trim();
var textarea = jQuery( '#' + editor.id );
textarea.val( content ).trigger( 'keyup' ).trigger( 'paste' ).trigger( 'mouseover' );
});}" ),
), $this, $form, $entry );
$editor_settings = apply_filters( sprintf( 'gform_rich_text_editor_options_%d', $form['id'] ), $editor_settings, $this, $form, $entry );
$editor_settings = apply_filters( sprintf( 'gform_rich_text_editor_options_%d_%d', $form['id'], $this->id ), $editor_settings, $this, $form, $entry );
if ( ! has_action( 'wp_tiny_mce_init', array( __class__, 'start_wp_tiny_mce_init_buffer' ) ) ) {
add_action( 'wp_tiny_mce_init', array( __class__, 'start_wp_tiny_mce_init_buffer' ) );
}
ob_start();
wp_editor( $value, $field_id, $editor_settings );
$input = ob_get_clean();
remove_filter( 'mce_buttons', array( $this, 'filter_mce_buttons' ), 10 );
remove_filter( 'mce_buttons_2', array( $this, 'filter_mce_buttons' ), 10 );
remove_filter( 'mce_buttons_3', array( $this, 'filter_mce_buttons' ), 10 );
remove_filter( 'mce_buttons_4', array( $this, 'filter_mce_buttons' ), 10 );
} else {
$input = '';
$input_style = '';
// RTE preview
if ( $this->is_form_editor() ) {
$display = $this->useRichTextEditor ? 'block' : 'none';
$input_style = $this->useRichTextEditor ? 'style="display:none;"' : '';
$size = $this->size ? $this->size : 'medium';
$input = sprintf( '<div id="%s_rte_preview" class="gform-rte-preview %s" style="display:%s"></div>', $field_id, $size, $display );
}
$input .= "<textarea name='input_{$id}' id='{$field_id}' class='textarea {$class}' {$tabindex} {$aria_describedby} {$maxlength_attribute} {$placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text} {$input_style} rows='10' cols='50'>{$value}</textarea>";
}
return sprintf( "<div class='ginput_container ginput_container_textarea'>%s</div>", $input );
}
public function validate( $value, $form ) {
if ( ! is_numeric( $this->maxLength ) ) {
return;
}
if ( $this->useRichTextEditor ) {
$value = wp_specialchars_decode( $value );
}
// Clean the string of characters not counted by the textareaCounter plugin.
$value = strip_tags( $value );
$value = str_replace( "\r", '', $value );
$value = trim( $value );
if ( GFCommon::safe_strlen( $value ) > $this->maxLength ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'The text entered exceeds the maximum number of characters.', 'gravityforms' ) : $this->errorMessage;
}
}
public static function start_wp_tiny_mce_init_buffer() {
ob_start();
add_action( 'after_wp_tiny_mce', array( __class__, 'end_wp_tiny_mce_init_buffer' ), 1 );
}
public static function end_wp_tiny_mce_init_buffer() {
$script = ob_get_clean();
$pattern = '/(<script.*>)([\s\S]+)(<\/script>)/';
preg_match_all( $pattern, $script, $matches, PREG_SET_ORDER );
// Fix editor height issue: https://core.trac.wordpress.org/ticket/45461.
$wp_version = get_bloginfo( 'version' );
$height_issue_fix = version_compare( $wp_version, '5.0', '>=' ) && version_compare( $wp_version, '5.2', '<' ) ? ' gform_post_conditional_logic' : '';
foreach ( $matches as $match ) {
list( $search, $open_tag, $guts, $close_tag ) = $match;
$custom = "if ( typeof current_page === 'undefined' ) { return; }\nfor( var id in tinymce.editors ) { tinymce.EditorManager.remove( tinymce.editors[id] ); }";
$replace = sprintf( "%s\njQuery( document ).on( 'gform_post_render%s', function( event, form_id, current_page ) { \n%s\n%s } );\n%s", $open_tag, $height_issue_fix, $custom, $guts, $close_tag );
$script = str_replace( $search, $replace, $script );
}
echo $script;
}
public function filter_mce_buttons( $mce_buttons, $editor_id ) {
$remove_key = array_search( 'wp_more', $mce_buttons );
if ( $remove_key !== false ) {
unset( $mce_buttons[ $remove_key ] );
}
// Get current filter to detect which mce_buttons core filter is running.
$current_filter = current_filter();
// Depending on the current mce_buttons filter, set variable to support filtering all potential rows.
switch ( $current_filter ) {
case 'mce_buttons_2':
$mce_filter = '_row_two';
break;
case 'mce_buttons_3':
$mce_filter = '_row_three';
break;
case 'mce_buttons_4':
$mce_filter = '_row_four';
break;
default:
$mce_filter = '';
break;
}
/**
* Filters the buttons within the TinyMCE editor
*
* @since 2.0.0
*
* @param array $mce_buttons Buttons to be included.
* @param string $editor_id HTML ID of the field.
* @param object $this The field object
*
* Additional filters for specific form and fields IDs.
*/
$mce_buttons = gf_apply_filters( array( 'gform_rich_text_editor_buttons' . $mce_filter, $this->formId, $this->id ), $mce_buttons, $editor_id, $this );
return $mce_buttons;
}
/**
* Format the entry value for display on the entry detail page and for the {all_fields} merge tag.
* Return a value that's safe to display for the context of the given $format.
*
* @param string|array $value The field value.
* @param string $currency The entry currency code.
* @param bool|false $use_text When processing choice based fields should the choice text be returned instead of the value.
* @param string $format The format requested for the location the merge is being used. Possible values: html, text or url.
* @param string $media The location where the value will be displayed. Possible values: screen or email.
*
* @return string
*/
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( $format === 'html' ) {
$allowable_tags = $this->get_allowable_tags();
if ( $allowable_tags === false ) {
// The value is unsafe so encode the value.
$value = esc_html( $value );
$return = nl2br( $value );
} else {
// The value contains HTML but the value was sanitized before saving.
$return = wpautop( $value );
}
} else {
$return = $value;
}
return $return;
}
/**
* Format the entry value for when the field/input merge tag is processed. Not called for the {all_fields} merge tag.
*
* Return a value that is safe for the context specified by $format.
*
* @since Unknown
* @access public
*
* @param string|array $value The field value. Depending on the location the merge tag is being used the following functions may have already been applied to the value: esc_html, nl2br, and urlencode.
* @param string $input_id The field or input ID from the merge tag currently being processed.
* @param array $entry The Entry Object currently being processed.
* @param array $form The Form Object currently being processed.
* @param string $modifier The merge tag modifier. e.g. value
* @param string|array $raw_value The raw field value from before any formatting was applied to $value.
* @param bool $url_encode Indicates if the urlencode function may have been applied to the $value.
* @param bool $esc_html Indicates if the esc_html function may have been applied to the $value.
* @param string $format The format requested for the location the merge is being used. Possible values: html, text or url.
* @param bool $nl2br Indicates if the nl2br function may have been applied to the $value.
*
* @return string
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
if ( $format === 'html' ) {
$form_id = absint( $form['id'] );
$allowable_tags = $this->get_allowable_tags( $form_id );
if ( $allowable_tags === false ) {
// The raw value is unsafe so escape it.
$return = esc_html( $raw_value );
// Run nl2br() to preserve line breaks when auto-formatting is disabled on notifications/confirmations.
$return = nl2br( $return );
} else {
// The value contains HTML but the value was sanitized before saving.
$return = wpautop( $raw_value );
}
} else {
$return = $value;
}
return $return;
}
/**
* Determines if the RTE can be enabled for the current field and user.
*
* @since 2.2.5.14
*
* @return bool
*/
public function is_rich_edit_enabled() {
if ( ! $this->useRichTextEditor ) {
return false;
}
global $wp_rich_edit;
$wp_rich_edit = null;
add_filter( 'get_user_option_rich_editing', array( $this, 'filter_user_option_rich_editing' ) );
$user_can_rich_edit = user_can_richedit();
remove_filter( 'get_user_option_rich_editing', array( $this, 'filter_user_option_rich_editing' ) );
return $user_can_rich_edit;
}
/**
* Filter the rich_editing option for the current user.
*
* @since 2.2.5.14
*
* @param string $value The value of the rich_editing option for the current user.
*
* @return string
*/
public function filter_user_option_rich_editing( $value ) {
return 'true';
}
// # FIELD FILTER UI HELPERS ---------------------------------------------------------------------------------------
/**
* Returns the filter operators for the current field.
*
* @since 2.4
*
* @return array
*/
public function get_filter_operators() {
$operators = parent::get_filter_operators();
$operators[] = 'contains';
return $operators;
}
}
GF_Fields::register( new GF_Field_Textarea() );
class-gf-field-donation.php 0000666 00000004614 15126403614 0011661 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
/**
* @deprecated since 1.6
*
* Class GF_Field_Donationç
*/
class GF_Field_Donation extends GF_Field {
public $type = 'donation';
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'donation_field_type_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'admin_label_setting',
'label_placement_setting',
'rules_setting',
'default_value_setting',
'placeholder_setting',
'description_setting',
'css_class_setting',
);
}
public function get_form_editor_button() {
return array();
}
public function validate( $value, $form ) {
$price = GFCommon::to_number( $value );
if ( ! rgblank( $value ) && ( $price === false || $price < 0 ) ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'Please enter a valid amount.', 'gravityforms' ) : $this->errorMessage;
}
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = absint( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$value = esc_attr( $value );
$placeholder_attribute = $this->get_field_placeholder_attribute();
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$class = esc_attr( $class );
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$tabindex = $this->get_tabindex();
return "<div class='ginput_container ginput_container_donation'>
<input name='input_{$id}' id='{$field_id}' type='text' value='{$value}' class='{$class} ginput_donation_amount' {$tabindex} {$placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>
</div>";
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
return GFCommon::to_money( $value, $currency );
}
}
GF_Fields::register( new GF_Field_Donation() ); index.php 0000666 00000000033 15126403614 0006366 0 ustar 00 <?php
//Nothing to see here class-gf-field-name.php 0000666 00000074561 15126403614 0010776 0 ustar 00 <?php
// If Gravity Forms isn't loaded, bail.
if ( ! class_exists( 'GFForms' ) ) {
die();
}
/**
* Class GF_Field_Name
*
* Handles the behavior of the Name field.
*
* @since Unknown
*/
class GF_Field_Name extends GF_Field {
/**
* Sets the field type.
*
* @since Unknown
* @access public
*
* @var string The type of field.
*/
public $type = 'name';
/**
* Sets the field title of the Name field.
*
* @since Unknown
* @access public
*
* @used-by GFCommon::get_field_type_title()
* @used-by GF_Field::get_form_editor_button()
*
* @return string
*/
public function get_form_editor_field_title() {
return esc_attr__( 'Name', 'gravityforms' );
}
/**
* Defines if conditional logic is supported by the Name field.
*
* @since Unknown
* @access public
*
* @used-by GFFormDetail::inline_scripts()
* @used-by GFFormSettings::output_field_scripts()
*
* @return bool true
*/
public function is_conditional_logic_supported() {
return true;
}
/**
* Validates Name field inputs.
*
* @since Unknown
* @access public
*
* @used-by GFFormDisplay::validate()
* @uses GF_Field_Name::$isRequired
* @uses GF_Field_Name::$nameFormat
* @uses GF_Field_Name::get_input_property
* @uses GF_Field_Name::$failed_validation
* @uses GF_Field_Name::$validation_message
* @uses GF_Field_Name::$errorMessage
*
* @param array|string $value The value of the field to validate. Not used here.
* @param array $form The Form Object. Not used here.
*
* @return void
*/
function validate( $value, $form ) {
if ( $this->isRequired && $this->nameFormat != 'simple' ) {
$first = rgar( $value, $this->id . '.3' );
$last = rgar( $value, $this->id . '.6' );
if ( ( empty( $first ) && ! $this->get_input_property( '3', 'isHidden' ) )
|| ( empty( $last ) && ! $this->get_input_property( '6', 'isHidden' ) ) ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'This field is required. Please enter the first and last name.', 'gravityforms' ) : $this->errorMessage;
}
}
}
/**
* Defines the field settings available for the Name field in the form editor.
*
* @since Unknown
* @access public
*
* @used-by GFFormDetail::inline_scripts()
*
* @return array The field settings available.
*/
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'admin_label_setting',
'label_placement_setting',
'sub_label_placement_setting',
'default_input_values_setting',
'input_placeholders_setting',
'name_setting',
'rules_setting',
'visibility_setting',
'description_setting',
'css_class_setting',
);
}
/**
* Gets the HTML markup for the field input.
*
* @since Unknown
* @access public
*
* @used-by GFCommon::get_field_input()
* @uses GF_Field::is_entry_detail()
* @uses GF_Field::is_form_editor()
* @uses GF_Field_Name::$size
* @uses GF_Field_Name::$id
* @uses GF_Field_Name::$subLabelPlacement
* @uses GF_Field_Name::$isRequired
* @uses GF_Field_Name::$failed_validation
* @uses GFForms::get()
* @uses GFFormsModel::get_input()
* @uses GFCommon::get_input_placeholder_attribute()
* @uses GFCommon::get_tabindex()
* @uses GFCommon::get_field_placeholder_attribute()
* @uses GF_Field_Name::get_css_class()
*
* @param array $form The Form Object.
* @param string $value The value of the field. Defaults to empty string.
* @param array|null $entry The Entry Object. Defaults to null.
*
* @return string The HTML markup for the field input.
*/
public function get_field_input( $form, $value = '', $entry = null ) {
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$is_admin = $is_entry_detail || $is_form_editor;
$form_id = $form['id'];
$id = intval( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$form_id = ( $is_entry_detail || $is_form_editor ) && empty( $form_id ) ? rgget( 'id' ) : $form_id;
$size = $this->size;
$class_suffix = rgget('view') == 'entry' ? '_admin' : '';
$class = $size . $class_suffix;
$class = esc_attr( $class );
$disabled_text = $is_form_editor ? "disabled='disabled'" : '';
$class_suffix = $is_entry_detail ? '_admin' : '';
$form_sub_label_placement = rgar( $form, 'subLabelPlacement' );
$field_sub_label_placement = $this->subLabelPlacement;
$is_sub_label_above = $field_sub_label_placement == 'above' || ( empty( $field_sub_label_placement ) && $form_sub_label_placement == 'above' );
$sub_label_class_attribute = $field_sub_label_placement == 'hidden_label' ? "class='hidden_sub_label screen-reader-text'" : '';
$prefix = '';
$first = '';
$middle = '';
$last = '';
$suffix = '';
if ( is_array( $value ) ) {
$prefix = esc_attr( GFForms::get( $this->id . '.2', $value ) );
$first = esc_attr( GFForms::get( $this->id . '.3', $value ) );
$middle = esc_attr( GFForms::get( $this->id . '.4', $value ) );
$last = esc_attr( GFForms::get( $this->id . '.6', $value ) );
$suffix = esc_attr( GFForms::get( $this->id . '.8', $value ) );
}
$prefix_input = GFFormsModel::get_input( $this, $this->id . '.2' );
$first_input = GFFormsModel::get_input( $this, $this->id . '.3' );
$middle_input = GFFormsModel::get_input( $this, $this->id . '.4' );
$last_input = GFFormsModel::get_input( $this, $this->id . '.6' );
$suffix_input = GFFormsModel::get_input( $this, $this->id . '.8' );
$first_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $first_input );
$middle_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $middle_input );
$last_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $last_input );
$suffix_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $suffix_input );
// ARIA labels. Prefix is handled in self::get_name_prefix_field().
$first_name_aria_label = esc_attr__( 'First name', 'gravityforms' );
$middle_name_aria_label = esc_attr__( 'Middle name', 'gravityforms' );
$last_name_aria_label = esc_attr__( 'Last name', 'gravityforms' );
$suffix_aria_label = esc_attr__( 'Name suffix', 'gravityforms' );
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
switch ( $this->nameFormat ) {
case 'advanced' :
case 'extended' :
$prefix_tabindex = GFCommon::get_tabindex();
$first_tabindex = GFCommon::get_tabindex();
$middle_tabindex = GFCommon::get_tabindex();
$last_tabindex = GFCommon::get_tabindex();
$suffix_tabindex = GFCommon::get_tabindex();
$prefix_sub_label = rgar( $prefix_input, 'customLabel' ) != '' ? $prefix_input['customLabel'] : gf_apply_filters( array( 'gform_name_prefix', $form_id ), esc_html__( 'Prefix', 'gravityforms' ), $form_id );
$first_name_sub_label = rgar( $first_input, 'customLabel' ) != '' ? $first_input['customLabel'] : gf_apply_filters( array( 'gform_name_first', $form_id ), esc_html__( 'First', 'gravityforms' ), $form_id );
$middle_name_sub_label = rgar( $middle_input, 'customLabel' ) != '' ? $middle_input['customLabel'] : gf_apply_filters( array( 'gform_name_middle', $form_id ), esc_html__( 'Middle', 'gravityforms' ), $form_id );
$last_name_sub_label = rgar( $last_input, 'customLabel' ) != '' ? $last_input['customLabel'] : gf_apply_filters( array( 'gform_name_last', $form_id ), esc_html__( 'Last', 'gravityforms' ), $form_id );
$suffix_sub_label = rgar( $suffix_input, 'customLabel' ) != '' ? $suffix_input['customLabel'] : gf_apply_filters( array( 'gform_name_suffix', $form_id ), esc_html__( 'Suffix', 'gravityforms' ), $form_id );
$prefix_markup = '';
$first_markup = '';
$middle_markup = '';
$last_markup = '';
$suffix_markup = '';
if ( $is_sub_label_above ) {
$style = ( $is_admin && rgar( $prefix_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $prefix_input, 'isHidden' ) ) {
$prefix_select_class = isset( $prefix_input['choices'] ) && is_array( $prefix_input['choices'] ) ? 'name_prefix_select' : '';
$prefix_markup = self::get_name_prefix_field( $prefix_input, $id, $field_id, $prefix, $disabled_text, $prefix_tabindex );
$prefix_markup = "<span id='{$field_id}_2_container' class='name_prefix {$prefix_select_class}' {$style}>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$prefix_sub_label}</label>
{$prefix_markup}
</span>";
}
$style = ( $is_admin && rgar( $first_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $first_input, 'isHidden' ) ) {
$first_markup = "<span id='{$field_id}_3_container' class='name_first' {$style}>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$first_name_sub_label}</label>
<input type='text' name='input_{$id}.3' id='{$field_id}_3' value='{$first}' aria-label='{$first_name_aria_label}' {$first_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$first_placeholder_attribute}/>
</span>";
}
$style = ( $is_admin && ( ! isset( $middle_input['isHidden'] ) || rgar( $middle_input, 'isHidden' ) ) ) ? "style='display:none;'" : '';
if ( $is_admin || ( isset( $middle_input['isHidden'] ) && $middle_input['isHidden'] == false ) ) {
$middle_markup = "<span id='{$field_id}_4_container' class='name_middle' {$style}>
<label for='{$field_id}_4' {$sub_label_class_attribute}>{$middle_name_sub_label}</label>
<input type='text' name='input_{$id}.4' id='{$field_id}_4' value='{$middle}' aria-label='{$middle_name_aria_label}' {$middle_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$middle_placeholder_attribute}/>
</span>";
}
$style = ( $is_admin && rgar( $last_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $last_input, 'isHidden' ) ) {
$last_markup = "<span id='{$field_id}_6_container' class='name_last' {$style}>
<label for='{$field_id}_6' {$sub_label_class_attribute}>{$last_name_sub_label}</label>
<input type='text' name='input_{$id}.6' id='{$field_id}_6' value='{$last}' aria-label='{$last_name_aria_label}' {$last_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$last_placeholder_attribute}/>
</span>";
}
$style = ( $is_admin && rgar( $suffix_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $suffix_input, 'isHidden' ) ) {
$suffix_select_class = isset( $suffix_input['choices'] ) && is_array( $suffix_input['choices'] ) ? 'name_suffix_select' : '';
$suffix_markup = "<span id='{$field_id}_8_container' class='name_suffix {$suffix_select_class}' {$style}>
<label for='{$field_id}_8' {$sub_label_class_attribute}>{$suffix_sub_label}</label>
<input type='text' name='input_{$id}.8' id='{$field_id}_8' value='{$suffix}' aria-label='{$suffix_aria_label}' {$suffix_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$suffix_placeholder_attribute}/>
</span>";
}
} else {
$style = ( $is_admin && rgar( $prefix_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $prefix_input, 'isHidden' ) ) {
$prefix_select_class = isset( $prefix_input['choices'] ) && is_array( $prefix_input['choices'] ) ? 'name_prefix_select' : '';
$prefix_markup = self::get_name_prefix_field( $prefix_input, $id, $field_id, $prefix, $disabled_text, $prefix_tabindex );
$prefix_markup = "<span id='{$field_id}_2_container' class='name_prefix {$prefix_select_class}' {$style}>
{$prefix_markup}
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$prefix_sub_label}</label>
</span>";
}
$style = ( $is_admin && rgar( $first_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $first_input, 'isHidden' ) ) {
$first_markup = "<span id='{$field_id}_3_container' class='name_first' {$style}>
<input type='text' name='input_{$id}.3' id='{$field_id}_3' value='{$first}' aria-label='{$first_name_aria_label}' {$first_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$first_placeholder_attribute}/>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$first_name_sub_label}</label>
</span>";
}
$style = ( $is_admin && ( ! isset( $middle_input['isHidden'] ) || rgar( $middle_input, 'isHidden' ) ) ) ? "style='display:none;'" : '';
if ( $is_admin || ( isset( $middle_input['isHidden'] ) && $middle_input['isHidden'] == false ) ) {
$middle_markup = "<span id='{$field_id}_4_container' class='name_middle' {$style}>
<input type='text' name='input_{$id}.4' id='{$field_id}_4' value='{$middle}' aria-label='{$middle_name_aria_label}' {$middle_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$middle_placeholder_attribute}/>
<label for='{$field_id}_4' {$sub_label_class_attribute}>{$middle_name_sub_label}</label>
</span>";
}
$style = ( $is_admin && rgar( $last_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $last_input, 'isHidden' ) ) {
$last_markup = "<span id='{$field_id}_6_container' class='name_last' {$style}>
<input type='text' name='input_{$id}.6' id='{$field_id}_6' value='{$last}' aria-label='{$last_name_aria_label}' {$last_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$last_placeholder_attribute}/>
<label for='{$field_id}_6' {$sub_label_class_attribute}>{$last_name_sub_label}</label>
</span>";
}
$style = ( $is_admin && rgar( $suffix_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $suffix_input, 'isHidden' ) ) {
$suffix_select_class = isset( $suffix_input['choices'] ) && is_array( $suffix_input['choices'] ) ? 'name_suffix_select' : '';
$suffix_markup = "<span id='{$field_id}_8_container' class='name_suffix {$suffix_select_class}' {$style}>
<input type='text' name='input_{$id}.8' id='{$field_id}_8' value='{$suffix}' aria-label='{$suffix_aria_label}' {$suffix_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$suffix_placeholder_attribute}/>
<label for='{$field_id}_8' {$sub_label_class_attribute}>{$suffix_sub_label}</label>
</span>";
}
}
$css_class = $this->get_css_class();
return "<div class='ginput_complex{$class_suffix} ginput_container {$css_class}' id='{$field_id}'>
{$prefix_markup}
{$first_markup}
{$middle_markup}
{$last_markup}
{$suffix_markup}
</div>";
case 'simple' :
$value = esc_attr( $value );
$class = esc_attr( $class );
$tabindex = GFCommon::get_tabindex();
$placeholder_attribute = GFCommon::get_field_placeholder_attribute( $this );
return "<div class='ginput_container ginput_container_name'>
<input name='input_{$id}' id='{$field_id}' type='text' value='{$value}' class='{$class}' {$tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$placeholder_attribute}/>
</div>";
default :
$first_tabindex = GFCommon::get_tabindex();
$last_tabindex = GFCommon::get_tabindex();
$first_name_sub_label = rgar( $first_input, 'customLabel' ) != '' ? $first_input['customLabel'] : gf_apply_filters( array( 'gform_name_first', $form_id ), esc_html__( 'First', 'gravityforms' ), $form_id );
$last_name_sub_label = rgar( $last_input, 'customLabel' ) != '' ? $last_input['customLabel'] : gf_apply_filters( array( 'gform_name_last', $form_id ), esc_html__( 'Last', 'gravityforms' ), $form_id );
if ( $is_sub_label_above ) {
$first_markup = '';
$style = ( $is_admin && rgar( $first_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $first_input, 'isHidden' ) ) {
$first_markup = "<span id='{$field_id}_3_container' class='name_first' {$style}>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$first_name_sub_label}</label>
<input type='text' name='input_{$id}.3' id='{$field_id}_3' value='{$first}' aria-label='{$first_name_aria_label}' {$first_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$first_placeholder_attribute}/>
</span>";
}
$last_markup = '';
$style = ( $is_admin && rgar( $last_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $last_input, 'isHidden' ) ) {
$last_markup = "<span id='{$field_id}_6_container' class='name_last' {$style}>
<label for='{$field_id}_6' {$sub_label_class_attribute}>" . $last_name_sub_label . "</label>
<input type='text' name='input_{$id}.6' id='{$field_id}_6' value='{$last}' aria-label='{$last_name_aria_label}' {$last_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$last_placeholder_attribute}/>
</span>";
}
} else {
$first_markup = '';
$style = ( $is_admin && rgar( $first_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $first_input, 'isHidden' ) ) {
$first_markup = "<span id='{$field_id}_3_container' class='name_first' {$style}>
<input type='text' name='input_{$id}.3' id='{$field_id}_3' value='{$first}' aria-label='{$first_name_aria_label}' {$first_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$first_placeholder_attribute}/>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$first_name_sub_label}</label>
</span>";
}
$last_markup = '';
$style = ( $is_admin && rgar( $last_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $last_input, 'isHidden' ) ) {
$last_markup = "<span id='{$field_id}_6_container' class='name_last' {$style}>
<input type='text' name='input_{$id}.6' id='{$field_id}_6' value='{$last}' aria-label='{$last_name_aria_label}' {$last_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$last_placeholder_attribute}/>
<label for='{$field_id}_6' {$sub_label_class_attribute}>{$last_name_sub_label}</label>
</span>";
}
}
$css_class = $this->get_css_class();
return "<div class='ginput_complex{$class_suffix} ginput_container {$css_class}' id='{$field_id}'>
{$first_markup}
{$last_markup}
<div class='gf_clear gf_clear_complex'></div>
</div>";
}
}
/**
* Defines the CSS class to be applied to the field label.
*
* @since Unknown
* @access public
*
* @used-by GF_Field::get_field_content()
*
* @return string The CSS class.
*/
public function get_field_label_class() {
return 'gfield_label gfield_label_before_complex';
}
/**
* Sets the CSS class to be used by the field input.
*
* @since Unknown
* @access public
*
* @used-by GF_Field_Name::get_field_input()
* @uses GFFormsModel::get_input()
*
* @return string The CSS class to use for the field.
*/
public function get_css_class() {
$prefix_input = GFFormsModel::get_input( $this, $this->id . '.2' );
$first_input = GFFormsModel::get_input( $this, $this->id . '.3' );
$middle_input = GFFormsModel::get_input( $this, $this->id . '.4' );
$last_input = GFFormsModel::get_input( $this, $this->id . '.6' );
$suffix_input = GFFormsModel::get_input( $this, $this->id . '.8' );
$css_class = '';
$visible_input_count = 0;
if ( $prefix_input && ! rgar( $prefix_input, 'isHidden' ) ) {
$visible_input_count++;
$css_class .= 'has_prefix ';
} else {
$css_class .= 'no_prefix ';
}
if ( $first_input && ! rgar( $first_input, 'isHidden' ) ) {
$visible_input_count++;
$css_class .= 'has_first_name ';
} else {
$css_class .= 'no_first_name ';
}
if ( $middle_input && ! rgar( $middle_input, 'isHidden' ) ) {
$visible_input_count++;
$css_class .= 'has_middle_name ';
} else {
$css_class .= 'no_middle_name ';
}
if ( $last_input && ! rgar( $last_input, 'isHidden' ) ) {
$visible_input_count++;
$css_class .= 'has_last_name ';
} else {
$css_class .= 'no_last_name ';
}
if ( $suffix_input && ! rgar( $suffix_input, 'isHidden' ) ) {
$visible_input_count++;
$css_class .= 'has_suffix ';
} else {
$css_class .= 'no_suffix ';
}
$css_class .= "gf_name_has_{$visible_input_count} ginput_container_name ";
return trim( $css_class );
}
/**
* Defines the field markup to be used for the name prefix.
*
* @since Unknown
* @access public
*
* @used-by GF_Field_Name::get_field_input()
* @uses GFCommon::get_input_placeholder_value()
* @uses GFCommon::get_input_placeholder_attribute()
*
* @param array $input The input item choices.
* @param int $id The ID of the name field.
* @param int $field_id The field ID of the name field.
* @param string $value The value to be used in the prefix field item.
* @param string $disabled_text The text to be used if the prefix field item is disabled.
* @param int $tabindex The tab index of the prefix field item.
*
* @return string The field HTML markup.
*/
public static function get_name_prefix_field( $input, $id, $field_id, $value, $disabled_text, $tabindex ) {
$prefix_aria_label = esc_attr__( 'Name prefix', 'gravityforms' );
if ( isset( $input['choices'] ) && is_array( $input['choices'] ) ) {
$placeholder_value = GFCommon::get_input_placeholder_value( $input );
$options = "<option value=''>{$placeholder_value}</option>";
$value_enabled = rgar( $input, 'enableChoiceValue' );
foreach ( $input['choices'] as $choice ) {
$choice_value = $value_enabled ? $choice['value'] : $choice['text'];
$is_selected_by_default = rgar( $choice, 'isSelected' );
$is_this_choice_selected = empty( $value ) ? $is_selected_by_default : strtolower( $choice_value ) == strtolower( $value );
$selected = $is_this_choice_selected ? "selected='selected'" : '';
$options .= "<option value='{$choice_value}' {$selected}>{$choice['text']}</option>";
}
$markup = "<select name='input_{$id}.2' id='{$field_id}_2' aria-label='{$prefix_aria_label}' {$tabindex} {$disabled_text}>
{$options}
</select>";
} else {
$placeholder_attribute = GFCommon::get_input_placeholder_attribute( $input );
$markup = "<input type='text' name='input_{$id}.2' id='{$field_id}_2' value='{$value}' aria-label='{$prefix_aria_label}' {$tabindex} {$disabled_text} {$placeholder_attribute}/>";
}
return $markup;
}
/**
* Gets the field value to be displayed on the entry detail page.
*
* @since Unknown
* @access public
*
* @used-by GFCommon::get_lead_field_display()
* @uses GF_Field_Name::$id
*
* @param array|string $value The value of the field input.
* @param string $currency Not used.
* @param bool $use_text Not used.
* @param string $format The format to output the value. Defaults to 'html'.
* @param string $media Not used.
*
* @return array|string The value to be displayed on the entry detail page.
*/
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( is_array( $value ) ) {
$prefix = trim( rgget( $this->id . '.2', $value ) );
$first = trim( rgget( $this->id . '.3', $value ) );
$middle = trim( rgget( $this->id . '.4', $value ) );
$last = trim( rgget( $this->id . '.6', $value ) );
$suffix = trim( rgget( $this->id . '.8', $value ) );
$name = $prefix;
$name .= ! empty( $name ) && ! empty( $first ) ? " $first" : $first;
$name .= ! empty( $name ) && ! empty( $middle ) ? " $middle" : $middle;
$name .= ! empty( $name ) && ! empty( $last ) ? " $last" : $last;
$name .= ! empty( $name ) && ! empty( $suffix ) ? " $suffix" : $suffix;
$return = $name;
} else {
$return = $value;
}
if ( $format === 'html' ) {
$return = esc_html( $return );
}
return $return;
}
/**
* Gets a property value from an input.
*
* @since Unknown
* @access public
*
* @used-by GF_Field_Name::validate()
* @uses GFFormsModel::get_input()
*
* @param int $input_id The input ID to obtain the property from.
* @param string $property_name The property name to search for.
*
* @return null|string The property value if found. Otherwise, null.
*/
public function get_input_property( $input_id, $property_name ) {
$input = GFFormsModel::get_input( $this, $this->id . '.' . (string) $input_id );
return rgar( $input, $property_name );
}
/**
* Sanitizes the field settings choices.
*
* @since Unknown
* @access public
*
* @used-by GFFormDetail::add_field()
* @used-by GFFormsModel::sanitize_settings()
* @uses GF_Field::sanitize_settings()
* @uses GF_Field::sanitize_settings_choices()
*
* @return void
*/
public function sanitize_settings() {
parent::sanitize_settings();
if ( is_array( $this->inputs ) ) {
foreach ( $this->inputs as &$input ) {
if ( isset ( $input['choices'] ) && is_array( $input['choices'] ) ) {
$input['choices'] = $this->sanitize_settings_choices( $input['choices'] );
}
}
}
}
/**
* Gets the field value to be used when exporting.
*
* @since Unknown
* @access public
*
* @used-by GFExport::start_export()
* @used-by GFAddOn::get_field_value()
* @used-by GFAddOn::get_full_name()
*
* @param array $entry The Entry Object.
* @param string $input_id The input ID to format. Defaults to empty string. If not set, uses t
* @param bool $use_text Not used.
* @param bool $is_csv Not used.
*
* @return string The field value.
*/
public function get_value_export( $entry, $input_id = '', $use_text = false, $is_csv = false ) {
if ( empty( $input_id ) ) {
$input_id = $this->id;
}
if ( absint( $input_id ) == $input_id ) {
// If field is simple (one input), simply return full content.
$name = rgar( $entry, $input_id );
if ( ! empty( $name ) ) {
return $name;
}
// Complex field (multiple inputs). Join all pieces and create name.
$prefix = trim( rgar( $entry, $input_id . '.2' ) );
$first = trim( rgar( $entry, $input_id . '.3' ) );
$middle = trim( rgar( $entry, $input_id . '.4' ) );
$last = trim( rgar( $entry, $input_id . '.6' ) );
$suffix = trim( rgar( $entry, $input_id . '.8' ) );
$name = $prefix;
$name .= ! empty( $name ) && ! empty( $first ) ? ' ' . $first : $first;
$name .= ! empty( $name ) && ! empty( $middle ) ? ' ' . $middle : $middle;
$name .= ! empty( $name ) && ! empty( $last ) ? ' ' . $last : $last;
$name .= ! empty( $name ) && ! empty( $suffix ) ? ' ' . $suffix : $suffix;
return $name;
} else {
return rgar( $entry, $input_id );
}
}
/**
* Removes the "for" attribute in the field label. Inputs are only allowed one label (a11y) and the inputs already have labels.
*
* @since 2.4
* @access public
*
* @param array $form The Form Object currently being processed.
*
* @return string
*/
public function get_first_input_id( $form ) {
return '';
}
// # FIELD FILTER UI HELPERS ---------------------------------------------------------------------------------------
/**
* Returns the sub-filters for the current field.
*
* @since 2.4
*
* @return array
*/
public function get_filter_sub_filters() {
$sub_filters = array();
if ( $this->nameFormat == 'simple' ) {
return $sub_filters;
}
$inputs = $this->inputs;
foreach ( (array) $inputs as $input ) {
if ( rgar( $input, 'isHidden' ) ) {
continue;
}
$sub_filters[] = array(
'key' => rgar( $input, 'id' ),
'text' => rgar( $input, 'customLabel', rgar( $input, 'label' ) ),
'preventMultiple' => false,
'operators' => $this->get_filter_operators(),
);
}
return $sub_filters;
}
/**
* Returns the filter operators for the current field.
*
* @since 2.4
*
* @return array
*/
public function get_filter_operators() {
$operators = parent::get_filter_operators();
$operators[] = 'contains';
return $operators;
}
}
// Registers the Name field with the field framework.
GF_Fields::register( new GF_Field_Name() );
class-gf-field-list.php 0000666 00000055616 15126403614 0011031 0 ustar 00 <?php
// If Gravity Forms isn't loaded, bail.
if ( ! class_exists( 'GFForms' ) ) {
die();
}
/**
* Class GF_Field_List
*
* Handles the behavior of List fields.
*
* @since Unknown
*/
class GF_Field_List extends GF_Field {
/**
* Sets the field type for the List field.
*
* @since Unknown
* @access public
*
* @var string The field type.
*/
public $type = 'list';
/**
* Sets the field title to be displayed in the form editor.
*
* @since Unknown
* @access public
*
* @return string The field title. Escaped and translatable.
*/
public function get_form_editor_field_title() {
return esc_attr__( 'List', 'gravityforms' );
}
/**
* Defines the field settings available in the form editor.
*
* @since Unknown
* @access public
*
* @used-by GFFormDetail::inline_scripts()
*
* @return array The settings available.
*/
function get_form_editor_field_settings() {
return array(
'columns_setting',
'maxrows_setting',
'add_icon_url_setting',
'delete_icon_url_setting',
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'rules_setting',
'visibility_setting',
'description_setting',
'css_class_setting',
);
}
/**
* Gets the ID of the first input.
*
* @since Unknown
* @access public
*
* @uses GF_Field::is_form_editor()
* @uses GF_Field_List::$id
*
* @param array $form The Form Object.
*
* @return string The ID of the first input. Empty string if not found.
*/
public function get_first_input_id( $form ) {
return '';
}
/**
* Defines if the inline style block has been printed.
*
* @since Unknown
* @access private
*
* @var bool false
*/
private static $_style_block_printed = false;
/**
* Builds the field input HTML markup.
*
* @since Unknown
* @access public
*
* @param array $form The Form Object.
* @param string $value The field value. Defaults to empty string.
* @param null|array $entry The Entry Object. Defaults to null.
*
* @return string The List field HTML markup.
*/
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = $form['id'];
$is_form_editor = $this->is_form_editor();
if ( ! empty( $value ) ) {
$value = maybe_unserialize( $value );
}
if ( is_array( $value ) ) {
if ( ! is_array( $value[0] ) ) {
$value = $this->create_list_array( $value );
}
} else {
$value = array( array() );
}
$has_columns = is_array( $this->choices );
$columns = $has_columns ? $this->choices : array( array() );
$list = '';
if ( ! self::$_style_block_printed ){
// This style block needs to be inline so that the list field continues to work even if the option to turn off CSS output is activated.
$list .= '<style type="text/css">
body .ginput_container_list table.gfield_list tbody tr td.gfield_list_icons {
vertical-align: middle !important;
}
body .ginput_container_list table.gfield_list tbody tr td.gfield_list_icons img {
background-color: transparent !important;
background-position: 0 0;
background-size: 16px 16px !important;
background-repeat: no-repeat;
border: none !important;
width: 16px !important;
height: 16px !important;
opacity: 0.5;
transition: opacity .5s ease-out;
-moz-transition: opacity .5s ease-out;
-webkit-transition: opacity .5s ease-out;
-o-transition: opacity .5s ease-out;
}
body .ginput_container_list table.gfield_list tbody tr td.gfield_list_icons a:hover img {
opacity: 1.0;
}
</style>';
self::$_style_block_printed = true;
}
$list .= "<div class='ginput_container ginput_container_list ginput_list'>" .
"<table class='gfield_list gfield_list_container'>";
if ( $has_columns ) {
$list .= '<colgroup>';
for ( $colnum = 1; $colnum <= count( $columns ) + 1; $colnum++ ) {
$odd_even = ( $colnum % 2 ) == 0 ? 'even' : 'odd';
$list .= sprintf( "<col id='gfield_list_%d_col_%d' class='gfield_list_col_%s' />", $this->id, $colnum, $odd_even );
}
$list .= '</colgroup>';
$list .= '<thead><tr>';
foreach ( $columns as $column ) {
// a11y: scope="col"
$list .= '<th scope="col">' . esc_html( $column['text'] ) . '</th>';
}
if ( $this->maxRows != 1 ) {
// Using td instead of th because empty th tags break a11y.
$list .= '<td> </td>';
}
$list .= '</tr></thead>';
} else {
$list .=
'<colgroup>' .
"<col id='gfield_list_{$this->id}_col1' class='gfield_list_col_odd' />" .
"<col id='gfield_list_{$this->id}_col2' class='gfield_list_col_even' />" .
'</colgroup>';
}
$delete_display = count( $value ) == 1 ? 'style="visibility:hidden;"' : '';
$maxRow = intval( $this->maxRows );
$disabled_icon_class = ! empty( $maxRow ) && count( $value ) >= $maxRow ? 'gfield_icon_disabled' : '';
$add_icon = ! empty( $this->addIconUrl ) ? $this->addIconUrl : GFCommon::get_base_url() . '/images/list-add.svg';
$delete_icon = ! empty( $this->deleteIconUrl ) ? $this->deleteIconUrl : GFCommon::get_base_url() . '/images/list-remove.svg';
$add_events = $is_form_editor ? '' : "onclick='gformAddListItem(this, {$maxRow})' onkeypress='gformAddListItem(this, {$maxRow})'";
$delete_events = $is_form_editor ? '' : "onclick='gformDeleteListItem(this, {$maxRow})' onkeypress='gformDeleteListItem(this, {$maxRow})'";
$list .= '<tbody>';
$rownum = 1;
foreach ( $value as $item ) {
$odd_even = ( $rownum % 2 ) == 0 ? 'even' : 'odd';
$list .= "<tr class='gfield_list_row_{$odd_even} gfield_list_group'>";
$colnum = 1;
foreach ( $columns as $column ) {
$data_label = '';
// Getting value. Taking into account columns being added/removed from form meta.
if ( is_array( $item ) ) {
if ( $has_columns ) {
$val = rgar( $item, $column['text'] );
$data_label = "data-label='" . esc_attr( $column['text'] ) . "'";
} else {
$vals = array_values( $item );
$val = rgar( $vals, 0 );
}
} else {
$val = $colnum == 1 ? $item : '';
}
$list .= "<td class='gfield_list_cell gfield_list_{$this->id}_cell{$colnum}' {$data_label}>" . $this->get_list_input( $has_columns, $column, $val, $form_id ) . '</td>';
$colnum ++;
}
if ( $this->maxRows != 1 ) {
// Can't replace these icons with the webfont versions since they appear on the front end.
$list .= "<td class='gfield_list_icons'>";
$list .= " <a href='javascript:void(0);' class='add_list_item {$disabled_icon_class}' aria-label='" . esc_attr__( 'Add another row', 'gravityforms' ) . "' {$add_events}><img src='{$add_icon}' alt='' title='" . esc_attr__( 'Add a new row', 'gravityforms' ) . "' /></a>" .
" <a href='javascript:void(0);' class='delete_list_item' aria-label='" . esc_attr__( 'Remove this row', 'gravityforms' ) . "' {$delete_events} {$delete_display}><img src='{$delete_icon}' alt='' title='" . esc_attr__( 'Remove this row', 'gravityforms' ) . "' /></a>";
$list .= '</td>';
}
$list .= '</tr>';
if ( ! empty( $maxRow ) && $rownum >= $maxRow ) {
break;
}
$rownum ++;
}
$list .= '</tbody>';
$list .= '</table></div>';
return $list;
}
/**
* Builds the input that will be inside the List field.
*
* @since Unknown
* @access public
*
* @param bool $has_columns If the input has columns.
* @param array $column The column details.
* @param string $value The existing value of the input.
* @param int $form_id The form ID.
*
* @return string The input HTML markup.
*/
public function get_list_input( $has_columns, $column, $value, $form_id ) {
$tabindex = $this->get_tabindex();
$disabled = $this->is_form_editor() ? 'disabled' : '';
$column_index = 1;
if ( $has_columns && is_array( $this->choices ) ) {
foreach ( $this->choices as $choice ) {
if ( $choice['text'] == $column['text'] ) {
break;
}
$column_index ++;
}
}
$input_info = array( 'type' => 'text' );
$column_text = rgar( $column, 'text' );
$aria_label = isset( $column['text'] ) ? $column_text : $this->label;
/**
* Filters the column input.
*
* @since Unknown
*
* @param array $input_info Information about the input. Contains the input type.
* @param object GF_Field_List Field object for this field type.
* @param string $column['text'] The column text value.
* @param int $form_id The form ID.
*/
$input_info = gf_apply_filters( array(
'gform_column_input',
$form_id,
$this->id,
$column_index
), $input_info, $this, $column_text, $value, $form_id );
switch ( $input_info['type'] ) {
case 'select' :
$input = "<select name='input_{$this->id}[]' {$tabindex} {$disabled} >";
if ( ! is_array( $input_info['choices'] ) ) {
$input_info['choices'] = array_map( 'trim', explode( ',', $input_info['choices'] ) );
}
foreach ( $input_info['choices'] as $choice ) {
if ( is_array( $choice ) ) {
$choice_value = $choice['value'];
$choice_text = $choice['text'];
$choice_selected = array_key_exists( 'isSelected', $choice ) ? $choice['isSelected'] : false;
} else {
$choice_value = $choice;
$choice_text = $choice;
$choice_selected = false;
}
$is_selected = empty( $value ) ? $choice_selected : $choice_value == $value;
$selected = $is_selected ? "selected='selected'" : '';
$input .= "<option value='" . esc_attr( $choice_value ) . "' {$selected}>" . esc_html( $choice_text ) . '</option>';
}
$input .= '</select>';
break;
default :
// a11y: inputs without a label must have the aria-label attribute set.
$input = "<input aria-label='" . esc_attr( $aria_label ) . "' type='text' name='input_{$this->id}[]' value='" . esc_attr( $value ) . "' {$tabindex} {$disabled}/>";
break;
}
/**
* Filters the column input HTML markup.
*
* @since Unknown
*
* @param string $input The input markup.
* @param array $input_info The information that was used to build the input.
* @param object GF_Field_List An instance of the List field object.
* @param string $column['text'] The column text value.
* @param int $form_id The form ID.
*/
return gf_apply_filters( array(
'gform_column_input_content',
$form_id,
$this->id,
$column_index
), $input, $input_info, $this, rgar( $column, 'text' ), $value, $form_id );
}
/**
* Gets the CSS class to be used in the field label.
*
* @since Unknown
* @access public
*
* @used-by GF_Field::get_field_content()
*
* @return string String containing the CSS class names.
*/
public function get_field_label_class(){
$has_columns = is_array( $this->choices );
return $has_columns ? 'gfield_label gfield_label_before_complex' : 'gfield_label';
}
/**
* Whether this field expects an array during submission.
*
* @since 2.4
*
* @return bool
*/
public function is_value_submission_array() {
return true;
}
/**
* Gets the value of te field from the form submission.
*
* @since Unknown
* @access public
*
* @param array $field_values The properties to search for.
* @param bool $get_from_post_global_var If the global GET variable should be used to obtain the value. Defaults to true.
*
* @return array The submission value.
*/
public function get_value_submission( $field_values, $get_from_post_global_var = true ) {
$value = $this->get_input_value_submission( 'input_' . $this->id, $this->inputName, $field_values, $get_from_post_global_var );
return $value;
}
/**
* Creates an array from the list items. Recurses if the field is inside a Repeater.
*
* @since 2.4
*
* @param $value
*
* @return array
*/
public function create_list_array_recursive( $value ) {
if ( isset( $value[0] ) && is_array( $value[0] ) ) {
$new_value = array();
foreach ( $value as $k => $v ) {
$new_value[ $k ] = $this->create_list_array_recursive( $v );
}
} else {
$new_value = $this->create_list_array( $value );
}
return $new_value;
}
/**
* Check if the submission value is empty.
*
* @since Unknown
* @access public
*
* @param int $form_id The form ID to check.
*
* @return bool True if empty. False otherwise.
*/
public function is_value_submission_empty( $form_id ) {
$value = rgpost( 'input_' . $this->id );
if ( is_array( $value ) ) {
// Empty if all inputs are empty (for inputs with the same name).
foreach ( $value as $input ) {
if ( strlen( trim( $input ) ) > 0 ) {
return false;
}
}
}
return true;
}
/**
* Gets the field value HTML markup to be used on the entry detail page.
*
* @since Unknown
* @access public
*
* @param array $value The submitted entry value.
* @param string $currency Not used.
* @param bool $use_text Not used.
* @param string $format The format to be used when building the items.
* Accepted values are text, url, or html. Defaults to html.
* @param string $media Defines how the content will be output.
* Accepted values are screen or email. Defaults to screen.
*
* @return string The HTML markup to be displayed.
*/
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( empty( $value ) ) {
return '';
}
$value = maybe_unserialize( $value );
if( ! is_array( $value ) || ! isset( $value[0] ) ) {
return '';
}
$has_columns = is_array( $value[0] );
if ( ! $has_columns ) {
$items = '';
foreach ( $value as $key => $item ) {
if ( ! empty( $item ) ) {
$item = wp_kses_post( $item );
switch ( $format ) {
case 'text' :
$items .= $item . ', ';
break;
case 'url' :
$items .= $item . ',';
break;
default :
if ( $media == 'email' ) {
$items .= "<li>{$item}</li>";
} else {
$items .= "<li>{$item}</li>";
}
break;
}
}
}
if ( empty( $items ) ) {
return '';
} elseif ( $format == 'text' ) {
return substr( $items, 0, strlen( $items ) - 2 ); // Removing last comma.
} elseif ( $format == 'url' ) {
return substr( $items, 0, strlen( $items ) - 1 ); // Removing last comma.
} elseif ( $media == 'email' ) {
return "<ul class='bulleted'>{$items}</ul>";
} else {
return "<ul class='bulleted'>{$items}</ul>";
}
} elseif ( is_array( $value ) ) {
$columns = array_keys( $value[0] );
$list = '';
switch ( $format ) {
case 'text' :
$is_first_row = true;
foreach ( $value as $item ) {
if ( ! $is_first_row ) {
$list .= "\n\n" . $this->label . ': ';
}
$item = array_map( 'wp_kses_post', $item );
$list .= implode( ',', array_values( $item ) );
$is_first_row = false;
}
break;
case 'url' :
foreach ( $value as $item ) {
$item = array_map( 'wp_kses_post', $item );
$list .= implode( "|", array_values( $item ) ) . ',';
}
if ( ! empty( $list ) ) {
$list = substr( $list, 0, strlen( $list ) - 1 );
}
break;
default :
if ( $media == 'email' ) {
$list = "<table class='gfield_list' style='border-top: 1px solid #DFDFDF; border-left: 1px solid #DFDFDF; border-spacing: 0; padding: 0; margin: 2px 0 6px; width: 100%'><thead><tr>\n";
//reading columns from entry data
foreach ( $columns as $column ) {
$list .= "<th style='background-image: none; border-right: 1px solid #DFDFDF; border-bottom: 1px solid #DFDFDF; padding: 6px 10px; font-family: sans-serif; font-size: 12px; font-weight: bold; background-color: #F1F1F1; color:#333; text-align:left'>" . esc_html( $column ) . '</th>' . "\n";
}
$list .= '</tr></thead>' . "\n";
$list .= "<tbody style='background-color: #F9F9F9'>";
foreach ( $value as $item ) {
$list .= '<tr>';
foreach ( $columns as $column ) {
$val = rgar( $item, $column );
$val = wp_kses_post( $val );
$list .= "<td style='padding: 6px 10px; border-right: 1px solid #DFDFDF; border-bottom: 1px solid #DFDFDF; border-top: 1px solid #FFF; font-family: sans-serif; font-size:12px;'>{$val}</td>\n";
}
$list .= '</tr>' . "\n";
}
$list .= '<tbody></table>' . "\n";
} else {
$list = "<table class='gfield_list'><thead><tr>";
// Reading columns from entry data.
foreach ( $columns as $column ) {
$list .= '<th scope="col">' . esc_html( $column ) . '</th>' . "\n";
}
$list .= '</tr></thead>' . "\n";
$list .= '<tbody>';
foreach ( $value as $item ) {
$list .= '<tr>';
foreach ( $columns as $column ) {
$val = rgar( $item, $column );
$val = wp_kses_post( $val );
$list .= "<td>{$val}</td>\n";
}
$list .= '</tr>' . "\n";
}
$list .= '<tbody></table>' . "\n";
}
break;
}
return $list;
}
return '';
}
/**
* Gets the value of the field when the entry is saved.
*
* @since Unknown
* @access public
*
* @param string $value The value to use.
* @param array $form The form that the entry is associated with.
* @param string $input_name The name of the input containing the value.
* @param int $lead_id The entry ID.
* @param array $lead The Entry Object.
*
* @return string The entry value. Escaped.
*/
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
if ( $this->is_administrative() && $this->allowsPrepopulate ) {
$value = json_decode( $value );
}
if ( GFCommon::is_empty_array( $value ) ) {
$value = '';
} else {
$value = $this->create_list_array( $value );
$value = serialize( $value );
}
$value_safe = $this->sanitize_entry_value( $value, $form['id'] );
return $value_safe;
}
/**
* Gets merge tag values.
*
* @since Unknown
* @access public
*
* @param array|string $value The value of the input.
* @param string $input_id The input ID to use.
* @param array $entry The Entry Object.
* @param array $form The Form Object
* @param string $modifier The modifier passed.
* @param array|string $raw_value The raw value of the input.
* @param bool $url_encode If the result should be URL encoded.
* @param bool $esc_html If the HTML should be escaped.
* @param string $format The format that the value should be.
* @param bool $nl2br If the nl2br function should be used.
*
* @return string The processed merge tag.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
$modifiers = $this->get_modifiers();
$allowed_modifiers = array( 'text', 'html', 'url' );
if( $found_modifiers = array_intersect( $modifiers, $allowed_modifiers ) ) {
$output_format = $found_modifiers[0];
} else {
$output_format = $format;
}
return GFCommon::get_lead_field_display( $this, $raw_value, $entry['currency'], true, $output_format );
}
/**
* Format the entry value for display on the entries list page.
*
* By default, the List field will not be available for selection on the entry list.
* Use the gform_display_field_select_columns_entry_list filter to make the list field available.
*
*
* @since 2.4
*
* @param string|array $value The field value.
* @param array $entry The Entry Object currently being processed.
* @param string $field_id The field or input ID currently being processed.
* @param array $columns The properties for the columns being displayed on the entry list page.
* @param array $form The Form Object currently being processed.
*
* @return string
*/
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
return GFCommon::get_lead_field_display( $this, $value, $entry['currency'], true, 'html' );
}
/**
* Creates an array from the list items.
*
* @since Unknown
* @access public
*
* @param array $value The pre-formatted list.
*
* @return array The list rows.
*/
function create_list_array( $value ) {
if ( ! $this->enableColumns ) {
return $value;
} else {
$value = empty( $value ) ? array() : $value;
$col_count = count( $this->choices );
$rows = array();
$row_count = count( $value ) / $col_count;
$col_index = 0;
for ( $i = 0; $i < $row_count; $i ++ ) {
$row = array();
foreach ( $this->choices as $column ) {
$row[ $column['text'] ] = rgar( $value, $col_index );
$col_index ++;
}
$rows[] = $row;
}
return $rows;
}
}
/**
* Sanitizes the field settings.
*
* @since Unknown
* @access public
*/
public function sanitize_settings() {
parent::sanitize_settings();
$this->maxRows = absint( $this->maxRows );
$this->enableColumns = (bool) $this->enableColumns;
}
/**
* Gets the field value, formatted for exports. For CSV export return an array.
*
* @since Unknown
* @access public
*
* @used-by GFExport::start_export()
* @used-by GFAddOn::get_field_value()
* @uses GF_Field_List::$id
* @uses GF_Field_List::$enableColumns
* @uses GF_Field_List::$choices
* @uses GFCommon::implode_non_blank()
*
* @param array $entry The Entry Object.
* @param string $input_id Input ID to export. If not defined, uses the current input ID. Defaults to empty string.
* @param bool $use_text Not used. Defaults to false.
* @param bool $is_csv Is the value going to be used in the CSV export? Defaults to false.
*
* @return string|array
*/
public function get_value_export( $entry, $input_id = '', $use_text = false, $is_csv = false ) {
if ( empty( $input_id ) ) {
$input_id = $this->id;
} elseif ( ! ctype_digit( $input_id ) ) {
$field_id_array = explode( '.', $input_id );
$input_id = rgar( $field_id_array, 0 );
$column_num = rgar( $field_id_array, 1 );
}
$value = rgar( $entry, $input_id );
$value = maybe_unserialize( $value );
if ( empty( $value ) || $is_csv ) {
return $value;
}
$list_values = $column_values = $value;
if ( isset( $column_num ) && is_numeric( $column_num ) && $this->enableColumns ) {
$column = rgars( $this->choices, "{$column_num}/text" );
$column_values = array();
foreach ( $list_values as $value ) {
$column_values[] = rgar( $value, $column );
}
} elseif ( $this->enableColumns ) {
return json_encode( $list_values );
}
return GFCommon::implode_non_blank( ', ', $column_values );
}
// # FIELD FILTER UI HELPERS ---------------------------------------------------------------------------------------
/**
* Returns the filter operators for the current field.
*
* @since 2.4
*
* @return array
*/
public function get_filter_operators() {
return array( 'contains' );
}
}
// Register the list field.
GF_Fields::register( new GF_Field_List() );
class-gf-fields.php 0000666 00000005014 15126403614 0010226 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
require_once( plugin_dir_path( __FILE__ ) . 'class-gf-field.php' );
class GF_Fields {
public static $deprecation_notice_fired = false;
/* @var GF_Field[] */
private static $_fields = array();
public static function register( $field ) {
if ( ! is_subclass_of( $field, 'GF_Field' ) ) {
throw new Exception( 'Must be a subclass of GF_Field' );
}
if ( empty( $field->type ) ) {
throw new Exception( 'The type must be set' );
}
if ( isset( self::$_fields[ $field->type ] ) ) {
throw new Exception( 'Field type already registered: ' . $field->type );
}
self::$_fields[ $field->type ] = $field;
}
public static function exists( $field_type ) {
return isset( self::$_fields[ $field_type ] );
}
/**
* @param $field_type
*
* @return GF_Field
*/
public static function get_instance( $field_type ) {
return isset( self::$_fields[ $field_type ] ) ? self::$_fields[ $field_type ] : false;
}
/**
* Alias for get_instance()
*
* @param $field_type
*
* @return GF_Field
*/
public static function get( $field_type ) {
return self::get_instance( $field_type );
}
/**
* Return all the registered field types.
*
* @return GF_Field[]
*/
public static function get_all() {
return self::$_fields;
}
/**
* Creates a Field object from an array of field properties.
*
* @param array|GF_Field $properties
*
* @return GF_Field | bool
*/
public static function create( $properties ) {
if ( $properties instanceof GF_Field ) {
$type = $properties->type;
$type = empty( $properties->inputType ) ? $type : $properties->inputType;
} else {
$type = isset( $properties['type'] ) ? $properties['type'] : '';
$type = empty( $properties['inputType'] ) ? $type : $properties['inputType'];
}
if ( empty( $type ) || ! isset( self::$_fields[ $type ] ) ) {
return new GF_Field( $properties );
}
$class = self::$_fields[ $type ];
$class_name = get_class( $class );
$field = new $class_name( $properties );
/**
* Filter the GF_Field object after it is created.
*
* @since 1.9.18.2
*
* @param GF_Field $field A GF_Field object.
* @param array $properties An array of field properties used to generate the GF_Field object.
*
* @see https://docs.gravityforms.com/gform_gf_field_create/
*/
return apply_filters( 'gform_gf_field_create', $field, $properties );
}
}
// Load all the field files automatically.
GFCommon::glob_require_once( '/includes/fields/class-gf-field-*.php' );
class-gf-field-password.php 0000666 00000037471 15126403614 0011717 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Password extends GF_Field {
public $type = 'password';
private static $passwords = array();
public function get_form_editor_field_title() {
return esc_attr__( 'Password', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'rules_setting',
'input_placeholders_setting',
'sub_label_placement_setting',
'description_setting',
'css_class_setting',
'password_strength_setting',
'password_visibility_setting',
'password_setting',
);
}
public function get_form_editor_button() {
return array(); // this button is conditionally added in the form detail page
}
public function get_entry_inputs() {
return null;
}
public function validate( $value, $form ) {
$password = rgpost( 'input_' . $this->id );
$confirm = rgpost( 'input_' . $this->id . '_2' );
if ( $this->is_confirm_input_enabled() && $password != $confirm ) {
$this->failed_validation = true;
$this->validation_message = esc_html__( 'Your passwords do not match.', 'gravityforms' );
} elseif ( $this->passwordStrengthEnabled && ! empty( $this->minPasswordStrength ) && ! empty( $password ) ) {
$strength = rgpost('input_' . $this->id . '_strength' );
if ( empty( $strength ) ) {
$strength = $this->get_password_strength( $password );
}
$levels = array( 'short' => 1, 'bad' => 2, 'good' => 3, 'strong' => 4 );
if ( rgar( $levels, $strength, 0 ) < $levels[ $this->minPasswordStrength ] ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? sprintf( esc_html__( 'Your password does not meet the required strength. %sHint: To make it stronger, use upper and lower case letters, numbers and symbols like ! " ? $ %% ^ & ).', 'gravityforms' ), '<br />' ) : $this->errorMessage;
}
}
}
/**
* Calculate the password score using PHP when not passed by JS.
*
* @since 2.4.11
*
* @see gravityforms.js gformPasswordStrength() JS code
*
* @param string $password The password that should be checked.
*
* @return string blank|short|bad|good|strong
*/
protected function get_password_strength( $password = '' ) {
$symbol_size = 0;
$strlen = GFCommon::safe_strlen( $password );
if ( 0 >= $strlen ) {
return 'blank';
}
if ( $strlen < 4 ) {
return 'short';
}
if ( preg_match( '/[ 0 - 9 ] /', $password ) ) {
$symbol_size += 10;
}
if ( preg_match( '/[ a - z ] /', $password ) ) {
$symbol_size += 26;
}
if ( preg_match( '/[ A - Z ] /', $password ) ) {
$symbol_size += 26;
}
if ( preg_match( '/[^a - zA - Z0 - 9]/', $password ) ) {
$symbol_size += 31;
}
$natLog = log( pow( $symbol_size, $strlen ) );
$score = $natLog / log( 2 );
if ( 40 > $score ) {
return 'bad';
}
if ( 56 > $score ) {
return 'good';
}
return 'strong';
}
public function get_field_input( $form, $value = '', $entry = null ) {
if ( is_array( $value ) ) {
$value = array_values( $value );
}
$form_id = $form['id'];
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$is_admin = $is_entry_detail || $is_form_editor;
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $this->is_confirm_input_enabled() ? '' : $size . $class_suffix; // Size only applies when confirmation is disabled.
$class = esc_attr( $class );
$form_sub_label_placement = rgar( $form, 'subLabelPlacement' );
$field_sub_label_placement = $this->subLabelPlacement;
$is_sub_label_above = $field_sub_label_placement == 'above' || ( empty( $field_sub_label_placement ) && $form_sub_label_placement == 'above' );
$sub_label_class_attribute = $field_sub_label_placement == 'hidden_label' ? "class='hidden_sub_label screen-reader-text'" : '';
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$first_tabindex = $this->get_tabindex();
$last_tabindex = $this->get_tabindex();
$strength_style = ! $this->passwordStrengthEnabled ? "style='display:none;'" : '';
$strength_indicator_label = esc_html__( 'Strength indicator', 'gravityforms' );
$strength = $this->passwordStrengthEnabled || $is_admin ? "<div id='{$field_id}_strength_indicator' class='gfield_password_strength' {$strength_style}>
{$strength_indicator_label}
</div>
<input type='hidden' class='gform_hidden' id='{$field_id}_strength' name='input_{$id}_strength' />" : '';
$action = ! $is_admin ? "gformShowPasswordStrength(\"$field_id\");" : '';
$onchange = $this->passwordStrengthEnabled ? "onchange='{$action}'" : '';
$onkeyup = $this->passwordStrengthEnabled ? "onkeyup='{$action}'" : '';
$confirmation_value = rgpost( 'input_' . $id . '_2' );
$password_value = is_array( $value ) ? $value[0] : $value;
$password_value = esc_attr( $password_value );
$confirmation_value = esc_attr( $confirmation_value );
$enter_password_field_input = GFFormsModel::get_input( $this, $this->id . '' );
$confirm_password_field_input = GFFormsModel::get_input( $this, $this->id . '.2' );
$enter_password_label = rgar( $enter_password_field_input, 'customLabel' ) != '' ? $enter_password_field_input['customLabel'] : esc_html__( 'Enter Password', 'gravityforms' );
$enter_password_label = gf_apply_filters( array( 'gform_password', $form_id ), $enter_password_label, $form_id );
$confirm_password_label = rgar( $confirm_password_field_input, 'customLabel' ) != '' ? $confirm_password_field_input['customLabel'] : esc_html__( 'Confirm Password', 'gravityforms' );
$confirm_password_label = gf_apply_filters( array( 'gform_password_confirm', $form_id ), $confirm_password_label, $form_id );
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$enter_password_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $enter_password_field_input );
$confirm_password_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $confirm_password_field_input );
$visibility_toggle_style = ! $this->passwordVisibilityEnabled ? " style='display:none;'" : '';
$enter_password_toggle = $this->passwordVisibilityEnabled || $is_admin ? "<button type='button' onclick='javascript:gformToggleShowPassword(\"{$field_id}\");' label='" . esc_attr__( 'Show Password', 'gravityforms' ) . "' data-label-show='" . esc_attr__( 'Show Password', 'gravityforms' ) . "' data-label-hide='" . esc_attr__( 'Hide Password', 'gravityforms' ) . "'{$visibility_toggle_style}><span class='dashicons dashicons-hidden' aria-hidden='true'></span></button>" : "";
$confirm_password_toggle = $this->passwordVisibilityEnabled || $is_admin ? "<button type='button' onclick='javascript:gformToggleShowPassword(\"{$field_id}_2\");' label='" . esc_attr__( 'Show Password', 'gravityforms' ) . "' data-label-show='" . esc_attr__( 'Show Password', 'gravityforms' ) . "' data-label-hide='" . esc_attr__( 'Hide Password', 'gravityforms' ) . "'{$visibility_toggle_style}><span class='dashicons dashicons-hidden' aria-hidden='true'></span></button>" : "";
if ( $is_form_editor ) {
$confirm_style = $this->is_confirm_input_enabled() ? '' : "style='display:none;'";
if ( $is_sub_label_above ) {
return "<div class='ginput_complex$class_suffix ginput_container ginput_container_password' id='{$field_id}_container'>
<span id='{$field_id}_1_container' class='ginput_left'>
<label for='{$field_id}' {$sub_label_class_attribute} {$confirm_style}>{$enter_password_label}</label>
<input type='password' name='input_{$id}' id='{$field_id}' {$onkeyup} {$onchange} value='{$password_value}' {$first_tabindex} {$enter_password_placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>
{$enter_password_toggle}
</span>
<span id='{$field_id}_2_container' class='ginput_right' {$confirm_style}>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$confirm_password_label}</label>
<input type='password' name='input_{$id}_2' id='{$field_id}_2' {$onkeyup} {$onchange} value='{$confirmation_value}' {$last_tabindex} {$confirm_password_placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>
{$confirm_password_toggle}
</span>
<div class='gf_clear gf_clear_complex'></div>
</div>{$strength}";
} else {
return "<div class='ginput_complex$class_suffix ginput_container ginput_container_password' id='{$field_id}_container'>
<span id='{$field_id}_1_container' class='ginput_left'>
<input type='password' name='input_{$id}' id='{$field_id}' {$onkeyup} {$onchange} value='{$password_value}' {$first_tabindex} {$enter_password_placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>
{$enter_password_toggle}
<label for='{$field_id}' {$sub_label_class_attribute} {$confirm_style}>{$enter_password_label}</label>
</span>
<span id='{$field_id}_2_container' class='ginput_right' {$confirm_style}>
<input type='password' name='input_{$id}_2' id='{$field_id}_2' {$onkeyup} {$onchange} value='{$confirmation_value}' {$last_tabindex} {$confirm_password_placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>
{$confirm_password_toggle}
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$confirm_password_label}</label>
</span>
<div class='gf_clear gf_clear_complex'></div>
</div>{$strength}";
}
}
if ( $this->is_confirm_input_enabled() ) {
if ( $is_sub_label_above ) {
return "<div class='ginput_complex$class_suffix ginput_container ginput_container_password' id='{$field_id}_container'>
<span id='{$field_id}_1_container' class='ginput_left'>
<label for='{$field_id}' {$sub_label_class_attribute}>{$enter_password_label}</label>
<input type='password' name='input_{$id}' id='{$field_id}' {$onkeyup} {$onchange} value='{$password_value}' {$first_tabindex} {$enter_password_placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>
{$enter_password_toggle}
</span>
<span id='{$field_id}_2_container' class='ginput_right'>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$confirm_password_label}</label>
<input type='password' name='input_{$id}_2' id='{$field_id}_2' {$onkeyup} {$onchange} value='{$confirmation_value}' {$last_tabindex} {$confirm_password_placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>
{$confirm_password_toggle}
</span>
<div class='gf_clear gf_clear_complex'></div>
</div>{$strength}";
} else {
return "<div class='ginput_complex$class_suffix ginput_container ginput_container_password' id='{$field_id}_container'>
<span id='{$field_id}_1_container' class='ginput_left'>
<input type='password' name='input_{$id}' id='{$field_id}' {$onkeyup} {$onchange} value='{$password_value}' {$first_tabindex} {$enter_password_placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>
{$enter_password_toggle}
<label for='{$field_id}' {$sub_label_class_attribute}>{$enter_password_label}</label>
</span>
<span id='{$field_id}_2_container' class='ginput_right'>
<input type='password' name='input_{$id}_2' id='{$field_id}_2' {$onkeyup} {$onchange} value='{$confirmation_value}' {$last_tabindex} {$confirm_password_placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>
{$confirm_password_toggle}
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$confirm_password_label}</label>
</span>
<div class='gf_clear gf_clear_complex'></div>
</div>{$strength}";
}
} else {
$class = esc_attr( $class );
return "<div class='ginput_container ginput_container_password'>
<span id='{$field_id}_1_container' class='{$size}'>
<input type='password' name='input_{$id}' id='{$field_id}' {$onkeyup} {$onchange} value='{$password_value}' {$first_tabindex} {$enter_password_placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>
{$enter_password_toggle}
</span>
<div class='gf_clear gf_clear_complex'></div>
</div>{$strength}";
}
}
public function get_field_label_class(){
return 'gfield_label gfield_label_before_complex';
}
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
/**
* A filter to allow the password to be encrypted (default set to false)
*
* @param bool Whether to encrypt the Password field with true or false
* @param array $form The Current Form Object
*/
$encrypt_password = apply_filters( 'gform_encrypt_password', false, $this, $form );
if ( $encrypt_password ) {
$value = GFCommon::openssl_encrypt( $value );
GFFormsModel::set_openssl_encrypted_fields( $lead_id, $this->id );
}
return $value;
}
/**
* @deprecated 2.4.16
*
* @param $entry
* @param $form
*/
public static function delete_passwords( $entry, $form ) {
$password_fields = GFAPI::get_fields_by_type( $form, array( 'password' ) );
$field_ids = array();
$encrypted_fields = GFFormsModel::get_openssl_encrypted_fields( $entry['id'] );
foreach ( $password_fields as $password_field ) {
$field_ids[] = $password_field->id;
GFAPI::update_entry_field( $entry['id'], $password_field->id, '' );
$key = array_search( $password_field->id, $encrypted_fields );
if ( $key !== false ) {
unset( $encrypted_fields[ $key ] );
}
}
if ( empty( $encrypted_fields ) ) {
gform_delete_meta( $entry['id'], '_openssl_encrypted_fields' );
} else {
gform_update_meta( $entry['id'], '_openssl_encrypted_fields', $encrypted_fields );
}
}
/**
* Removes the "for" attribute in the field label.
* Inputs are only allowed one label (a11y) and the inputs already have labels.
*
* @since 2.4
* @access public
*
* @param array $form The Form Object currently being processed.
*
* @return string
*/
public function get_first_input_id( $form ) {
return '';
}
/**
* Determines if the Confirm Password input is enabled.
*
* @since 2.4.15
*
* @return bool
*/
private function is_confirm_input_enabled() {
// Get Confirm Password input.
$confirm_input = GFFormsModel::get_input( $this, $this->id . '.2' );
return isset( $confirm_input['isHidden'] ) ? ! $confirm_input['isHidden'] : true;
}
/**
* Passwords are not saved to the database and won't be available in the runtime $entry object unless we stash and
* rehydrate them into the $entry object after it has been retrieved from the database.
*
* @since 2.4.16
*
* @param $form
*/
public static function stash_passwords( $form ) {
foreach( $form['fields'] as $field ) {
/* @var GF_Field $field */
if ( $field->get_input_type() == 'password' ) {
self::$passwords[ $field->id ] = $field->get_value_submission( rgpost( 'gform_field_values' ) );
}
}
}
/**
* Hydrate the stashed passwords back into the runtime $entry object that has just been saved and retrieved from the
* database.
*
* @since 2.4.16
*
* @param $entry
*
* @return array $entry
*/
public static function hydrate_passwords( $entry ) {
foreach( self::$passwords as $field_id => $password ) {
$entry[ $field_id ] = $password;
}
// Reset passwords so they are not available for the next submission in multi-submission requests (only possible via API).
self::$passwords = array();
return $entry;
}
}
GF_Fields::register( new GF_Field_Password() );
class-gf-field-select.php 0000666 00000014043 15126403614 0011322 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Select extends GF_Field {
public $type = 'select';
public function get_form_editor_field_title() {
return esc_attr__( 'Drop Down', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'enable_enhanced_ui_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'choices_setting',
'rules_setting',
'placeholder_setting',
'default_value_setting',
'visibility_setting',
'duplicate_setting',
'description_setting',
'css_class_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$css_class = trim( esc_attr( $class ) . ' gfield_select' );
$tabindex = $this->get_tabindex();
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
return sprintf( "<div class='ginput_container ginput_container_select'><select name='input_%d' id='%s' class='%s' $tabindex %s %s %s>%s</select></div>", $id, $field_id, $css_class, $disabled_text, $required_attribute, $invalid_attribute, $this->get_choices( $value ) );
}
public function get_choices( $value ) {
return GFCommon::get_select_choices( $this, $value );
}
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
$return = esc_html( $value );
return GFCommon::selection_display( $return, $this, $entry['currency'] );
}
/**
* Gets merge tag values.
*
* @since Unknown
* @access public
*
* @uses GFCommon::to_money()
* @uses GFCommon::format_post_category()
* @uses GFFormsModel::is_field_hidden()
* @uses GFFormsModel::get_choice_text()
* @uses GFCommon::format_variable_value()
* @uses GFCommon::implode_non_blank()
*
* @param array|string $value The value of the input.
* @param string $input_id The input ID to use.
* @param array $entry The Entry Object.
* @param array $form The Form Object
* @param string $modifier The modifier passed.
* @param array|string $raw_value The raw value of the input.
* @param bool $url_encode If the result should be URL encoded.
* @param bool $esc_html If the HTML should be escaped.
* @param string $format The format that the value should be.
* @param bool $nl2br If the nl2br function should be used.
*
* @return string The processed merge tag.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
$modifiers = $this->get_modifiers();
$use_value = in_array( 'value', $modifiers );
$format_currency = ! $use_value && in_array( 'currency', $modifiers );
$use_price = $format_currency || ( ! $use_value && in_array( 'price', $modifiers ) );
if ( is_array( $raw_value ) && (string) intval( $input_id ) != $input_id ) {
$items = array( $input_id => $value ); // Float input Ids. (i.e. 4.1 ). Used when targeting specific checkbox items.
} elseif ( is_array( $raw_value ) ) {
$items = $raw_value;
} else {
$items = array( $input_id => $raw_value );
}
$ary = array();
foreach ( $items as $input_id => $item ) {
if ( $use_value ) {
list( $val, $price ) = rgexplode( '|', $item, 2 );
} elseif ( $use_price ) {
list( $name, $val ) = rgexplode( '|', $item, 2 );
if ( $format_currency ) {
$val = GFCommon::to_money( $val, rgar( $entry, 'currency' ) );
}
} elseif ( $this->type == 'post_category' ) {
$use_id = strtolower( $modifier ) == 'id';
$item_value = GFCommon::format_post_category( $item, $use_id );
$val = RGFormsModel::is_field_hidden( $form, $this, array(), $entry ) ? '' : $item_value;
} else {
$val = RGFormsModel::is_field_hidden( $form, $this, array(), $entry ) ? '' : RGFormsModel::get_choice_text( $this, $raw_value, $input_id );
}
$ary[] = GFCommon::format_variable_value( $val, $url_encode, $esc_html, $format );
}
return GFCommon::implode_non_blank( ', ', $ary );
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
$return = esc_html( $value );
return GFCommon::selection_display( $return, $this, $currency, $use_text );
}
public function get_value_export( $entry, $input_id = '', $use_text = false, $is_csv = false ) {
if ( empty( $input_id ) ) {
$input_id = $this->id;
}
$value = rgar( $entry, $input_id );
return $is_csv ? $value : GFCommon::selection_display( $value, $this, rgar( $entry, 'currency' ), $use_text );
}
/**
* Strips all tags from the input value.
*
* @param string $value The field value to be processed.
* @param int $form_id The ID of the form currently being processed.
*
* @return string
*/
public function sanitize_entry_value( $value, $form_id ) {
$value = wp_strip_all_tags( $value );
return $value;
}
// # FIELD FILTER UI HELPERS ---------------------------------------------------------------------------------------
/**
* Returns the filter operators for the current field.
*
* @since 2.4
*
* @return array
*/
public function get_filter_operators() {
$operators = $this->type == 'product' ? array( 'is' ) : array( 'is', 'isnot', '>', '<' );
return $operators;
}
}
GF_Fields::register( new GF_Field_Select() );
class-gf-field-price.php 0000666 00000004264 15126403614 0011151 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Price extends GF_Field {
public $type = 'price';
function get_form_editor_field_settings() {
return array(
'rules_setting',
'conditional_logic_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'placeholder_setting',
'size_setting',
'duplicate_setting',
);
}
public function get_form_editor_button() {
return array();
}
public function validate( $value, $form ) {
$price = GFCommon::to_number( $value );
if ( ! rgblank( $value ) && ( $price === false || $price < 0 ) ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? __( 'Please enter a valid amount.', 'gravityforms' ) : $this->errorMessage;
}
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$value = esc_attr( $value );
$placeholder_attribute = $this->get_field_placeholder_attribute();
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$class = esc_attr( $class );
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$tabindex = $this->get_tabindex();
return "<div class='ginput_container ginput_container_product_price'>
<input name='input_{$id}' id='{$field_id}' type='text' value='{$value}' class='{$class} ginput_amount' {$tabindex} {$placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>
</div>";
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
return GFCommon::to_money( $value, $currency );
}
}
GF_Fields::register( new GF_Field_Price() ); class-gf-field-section.php 0000666 00000001641 15126403614 0011507 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Section extends GF_Field {
public $type = 'section';
public function get_form_editor_field_title() {
return esc_attr__( 'Section', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'label_setting',
'description_setting',
'visibility_setting',
'css_class_setting',
);
}
public function get_field_content( $value, $force_frontend_label, $form ) {
$field_label = $this->get_field_label( $force_frontend_label, $value );
$admin_buttons = $this->get_admin_buttons();
$description = $this->get_description( $this->description, 'gsection_description' );
$field_content = sprintf( "%s<h2 class='gsection_title'>%s</h2>%s", $admin_buttons, esc_html( $field_label ), $description );
return $field_content;
}
}
GF_Fields::register( new GF_Field_Section() ); class-gf-field-page.php 0000666 00000003326 15126403614 0010761 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Page extends GF_Field {
public $type = 'page';
public function get_form_editor_field_title() {
return esc_attr__( 'Page', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'next_button_setting',
'previous_button_setting',
'css_class_setting',
'conditional_logic_page_setting',
'conditional_logic_nextbutton_setting',
);
}
public function get_field_content( $value, $force_frontend_label, $form ) {
$admin_buttons = $this->get_admin_buttons();
$field_content = "{$admin_buttons} <label class='gfield_label'> </label><div class='gf-pagebreak-inline gf-pagebreak-container'><div class='gf-pagebreak-text-before'>" . esc_html__( 'end of page', 'gravityforms' ) . "</div><div class='gf-pagebreak-text-main'><span>" . esc_html__( 'PAGE BREAK', 'gravityforms' ) . "</span></div><div class='gf-pagebreak-text-after'>" . esc_html__( 'top of new page', 'gravityforms' ) . '</div></div>';
return $field_content;
}
public function sanitize_settings() {
parent::sanitize_settings();
if ( $this->nextButton ) {
$this->nextButton['imageUrl'] = wp_strip_all_tags( $this->nextButton['imageUrl'] );
$allowed_tags = wp_kses_allowed_html( 'post' );
$this->nextButton['text'] = wp_kses( $this->nextButton['text'], $allowed_tags );
$this->nextButton['type'] = wp_strip_all_tags( $this->nextButton['type'] );
if ( isset( $this->nextButton['conditionalLogic'] ) && is_array( $this->nextButton['conditionalLogic'] ) ) {
$this->nextButton['conditionalLogic'] = $this->sanitize_settings_conditional_logic( $this->nextButton['conditionalLogic'] );
}
}
}
}
GF_Fields::register( new GF_Field_Page() ); class-gf-field-fileupload.php 0000666 00000072665 15126403614 0012205 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_FileUpload extends GF_Field {
public $type = 'fileupload';
public function get_form_editor_field_title() {
return esc_attr__( 'File Upload', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'rules_setting',
'file_extensions_setting',
'file_size_setting',
'multiple_files_setting',
'visibility_setting',
'description_setting',
'css_class_setting',
);
}
public function validate( $value, $form ) {
$input_name = 'input_' . $this->id;
GFCommon::log_debug( __METHOD__ . '(): Validating field ' . $input_name );
$allowed_extensions = ! empty( $this->allowedExtensions ) ? GFCommon::clean_extensions( explode( ',', strtolower( $this->allowedExtensions ) ) ) : array();
if ( $this->multipleFiles ) {
$file_names = isset( GFFormsModel::$uploaded_files[ $form['id'] ][ $input_name ] ) ? GFFormsModel::$uploaded_files[ $form['id'] ][ $input_name ] : array();
} else {
$max_upload_size_in_bytes = isset( $this->maxFileSize ) && $this->maxFileSize > 0 ? $this->maxFileSize * 1048576 : wp_max_upload_size();
$max_upload_size_in_mb = $max_upload_size_in_bytes / 1048576;
if ( ! empty( $_FILES[ $input_name ]['name'] ) && $_FILES[ $input_name ]['error'] > 0 ) {
$uploaded_file_name = isset( GFFormsModel::$uploaded_files[ $form['id'] ][ $input_name ] ) ? GFFormsModel::$uploaded_files[ $form['id'] ][ $input_name ] : '';
if ( empty( $uploaded_file_name ) ) {
$this->failed_validation = true;
switch ( $_FILES[ $input_name ]['error'] ) {
case UPLOAD_ERR_INI_SIZE :
case UPLOAD_ERR_FORM_SIZE :
GFCommon::log_debug( __METHOD__ . '(): File ' . $_FILES[ $input_name ]['name'] . ' exceeds size limit. Maximum file size: ' . $max_upload_size_in_mb . 'MB' );
$fileupload_validation_message = sprintf( esc_html__( 'File exceeds size limit. Maximum file size: %dMB', 'gravityforms' ), $max_upload_size_in_mb );
break;
default :
GFCommon::log_debug( __METHOD__ . '(): The following error occurred while uploading - ' . $_FILES[ $input_name ]['error'] );
$fileupload_validation_message = sprintf( esc_html__( 'There was an error while uploading the file. Error code: %d', 'gravityforms' ), $_FILES[ $input_name ]['error'] );
}
$this->validation_message = empty( $this->errorMessage ) ? $fileupload_validation_message : $this->errorMessage;
return;
}
} elseif ( $_FILES[ $input_name ]['size'] > 0 && $_FILES[ $input_name ]['size'] > $max_upload_size_in_bytes ) {
$this->failed_validation = true;
GFCommon::log_debug( __METHOD__ . '(): File ' . $_FILES[ $input_name ]['name'] . ' exceeds size limit. Maximum file size: ' . $max_upload_size_in_mb . 'MB' );
$this->validation_message = sprintf( esc_html__( 'File exceeds size limit. Maximum file size: %dMB', 'gravityforms' ), $max_upload_size_in_mb );
return;
}
/**
* A filter to allow or disallow whitelisting when uploading a file
*
* @param bool false To set upload whitelisting to true or false (default is false, which means it is enabled)
*/
$whitelisting_disabled = apply_filters( 'gform_file_upload_whitelisting_disabled', false );
if ( ! empty( $_FILES[ $input_name ]['name'] ) && ! $whitelisting_disabled ) {
$check_result = GFCommon::check_type_and_ext( $_FILES[ $input_name ] );
if ( is_wp_error( $check_result ) ) {
$this->failed_validation = true;
GFCommon::log_debug( sprintf( '%s(): %s; %s', __METHOD__, $check_result->get_error_code(), $check_result->get_error_message() ) );
$this->validation_message = esc_html__( 'The uploaded file type is not allowed.', 'gravityforms' );
return;
}
}
$single_file_name = $_FILES[ $input_name ]['name'];
$file_names = array( array( 'uploaded_filename' => $single_file_name ) );
}
foreach ( $file_names as $file_name ) {
GFCommon::log_debug( __METHOD__ . '(): Validating file upload for ' . $file_name['uploaded_filename'] );
$info = pathinfo( rgar( $file_name, 'uploaded_filename' ) );
if ( empty( $allowed_extensions ) ) {
if ( GFCommon::file_name_has_disallowed_extension( rgar( $file_name, 'uploaded_filename' ) ) ) {
GFCommon::log_debug( __METHOD__ . '(): The file has a disallowed extension, failing validation.' );
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'The uploaded file type is not allowed.', 'gravityforms' ) : $this->errorMessage;
}
} else {
if ( ! empty( $info['basename'] ) && ! GFCommon::match_file_extension( rgar( $file_name, 'uploaded_filename' ), $allowed_extensions ) ) {
GFCommon::log_debug( __METHOD__ . '(): The file is of a type that cannot be uploaded, failing validation.' );
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? sprintf( esc_html__( 'The uploaded file type is not allowed. Must be one of the following: %s', 'gravityforms' ), strtolower( $this->allowedExtensions ) ) : $this->errorMessage;
}
}
}
GFCommon::log_debug( __METHOD__ . '(): Validation complete.' );
}
public function get_first_input_id( $form ) {
return $this->multipleFiles ? '' : 'input_' . $form['id'] . '_' . $this->id;
}
public function get_field_input( $form, $value = '', $entry = null ) {
$lead_id = absint( rgar( $entry, 'id' ) );
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = absint( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$class = esc_attr( $class );
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$tabindex = $this->get_tabindex();
$multiple_files = $this->multipleFiles;
$file_list_id = 'gform_preview_' . $form_id . '_' . $id;
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$is_admin = $is_entry_detail || $is_form_editor;
$max_upload_size = ! $is_admin && $this->maxFileSize > 0 ? $this->maxFileSize * 1048576 : wp_max_upload_size();
$allowed_extensions = ! empty( $this->allowedExtensions ) ? join( ',', GFCommon::clean_extensions( explode( ',', strtolower( $this->allowedExtensions ) ) ) ) : array();
if ( ! empty( $allowed_extensions ) ) {
$extensions_message = esc_attr( sprintf( __( 'Accepted file types: %s.', 'gravityforms' ), str_replace( ',', ', ', $allowed_extensions ) ) );
} else {
$extensions_message = '';
}
$extensions_message_id = 'extensions_message_' . $form_id . '_' . $id;
if ( $multiple_files ) {
$upload_action_url = trailingslashit( site_url() ) . '?gf_page=' . GFCommon::get_upload_page_slug();
$max_files = $this->maxFiles > 0 ? $this->maxFiles : 0;
$browse_button_id = 'gform_browse_button_' . $form_id . '_' . $id;
$container_id = 'gform_multifile_upload_' . $form_id . '_' . $id;
$drag_drop_id = 'gform_drag_drop_area_' . $form_id . '_' . $id;
$messages_id = "gform_multifile_messages_{$form_id}_{$id}";
if ( empty( $allowed_extensions ) ) {
$allowed_extensions = '*';
}
$disallowed_extensions = GFCommon::get_disallowed_file_extensions();
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && 'rg_change_input_type' === rgpost( 'action' ) ) {
$plupload_init = array();
} else {
$plupload_init = array(
'runtimes' => 'html5,flash,html4',
'browse_button' => $browse_button_id,
'container' => $container_id,
'drop_element' => $drag_drop_id,
'filelist' => $file_list_id,
'unique_names' => true,
'file_data_name' => 'file',
/*'chunk_size' => '10mb',*/ // chunking doesn't currently have very good cross-browser support
'url' => $upload_action_url,
'flash_swf_url' => includes_url( 'js/plupload/plupload.flash.swf' ),
'silverlight_xap_url' => includes_url( 'js/plupload/plupload.silverlight.xap' ),
'filters' => array(
'mime_types' => array( array( 'title' => __( 'Allowed Files', 'gravityforms' ), 'extensions' => $allowed_extensions ) ),
'max_file_size' => $max_upload_size . 'b',
),
'multipart' => true,
'urlstream_upload' => false,
'multipart_params' => array(
'form_id' => $form_id,
'field_id' => $id,
),
'gf_vars' => array(
'max_files' => $max_files,
'message_id' => $messages_id,
'disallowed_extensions' => $disallowed_extensions,
)
);
if ( rgar( $form, 'requireLogin' ) ) {
$plupload_init['multipart_params'][ '_gform_file_upload_nonce_' . $form_id ] = wp_create_nonce( 'gform_file_upload_' . $form_id, '_gform_file_upload_nonce_' . $form_id );
}
// plupload 2 was introduced in WordPress 3.9. Plupload 1 accepts a slightly different init array.
if ( version_compare( get_bloginfo( 'version' ), '3.9-RC1', '<' ) ) {
$plupload_init['max_file_size'] = $max_upload_size . 'b';
$plupload_init['filters'] = array( array( 'title' => __( 'Allowed Files', 'gravityforms' ), 'extensions' => $allowed_extensions ) );
}
}
$plupload_init = gf_apply_filters( array( 'gform_plupload_settings', $form_id ), $plupload_init, $form_id, $this );
$drop_files_here_text = esc_html__( 'Drop files here or', 'gravityforms' );
$select_files_text = esc_attr__( 'Select files', 'gravityforms' );
$plupload_init_json = htmlspecialchars( json_encode( $plupload_init ), ENT_QUOTES, 'UTF-8' );
$upload = "<div id='{$container_id}' data-settings='{$plupload_init_json}' class='gform_fileupload_multifile'>
<div id='{$drag_drop_id}' class='gform_drop_area'>
<span class='gform_drop_instructions'>{$drop_files_here_text} </span>
<input id='{$browse_button_id}' type='button' value='{$select_files_text}' class='button gform_button_select_files' aria-describedby='{$extensions_message_id}' {$tabindex} />
</div>
</div>";
if ( ! $is_admin ) {
$upload .= "<span id='{$extensions_message_id}' class='screen-reader-text'>{$extensions_message}</span>";
$upload .= "<div class='validation_message'>
<ul id='{$messages_id}'>
</ul>
</div>";
}
if ( $is_entry_detail ) {
$upload .= sprintf( '<input type="hidden" name="input_%d" value=\'%s\' />', $id, esc_attr( $value ) );
}
} else {
$upload = '';
if ( $max_upload_size <= 2047 * 1048576 ) {
// MAX_FILE_SIZE > 2048MB fails. The file size is checked anyway once uploaded, so it's not necessary.
$upload = sprintf( "<input type='hidden' name='MAX_FILE_SIZE' value='%d' />", $max_upload_size );
}
$validation_message_id = 'validation_message_' . $form_id . '_' . $id;
$live_validation_message_id= 'live_validation_message_' . $form_id . '_' . $id;
$upload .= sprintf( "<input name='input_%d' id='%s' type='file' class='%s' aria-describedby='%s %s %s' onchange='javascript:gformValidateFileSize( this, %s );' {$tabindex} %s/>", $id, $field_id, esc_attr( $class ), $validation_message_id, $live_validation_message_id, $extensions_message_id, esc_attr( $max_upload_size ), $disabled_text );
if ( ! $is_admin ) {
$upload .= "<span id='{$extensions_message_id}' class='screen-reader-text'>{$extensions_message}</span>";
$upload .= "<div class='validation_message' id='{$live_validation_message_id}'></div>";
}
}
if ( $is_entry_detail && ! empty( $value ) ) { // edit entry
$file_urls = $multiple_files ? json_decode( $value ) : array( $value );
$upload_display = $multiple_files ? '' : "style='display:none'";
$preview = "<div id='upload_$id' {$upload_display}>$upload</div>";
$preview .= sprintf( "<div id='%s'></div>", $file_list_id );
$preview .= sprintf( "<div id='preview_existing_files_%d'>", $id );
foreach ( $file_urls as $file_index => $file_url ) {
/**
* Allow for override of SSL replacement.
*
* By default Gravity Forms will attempt to determine if the schema of the URL should be overwritten for SSL.
* This is not ideal for all situations, particularly domain mapping. Setting $field_ssl to false will prevent
* the override.
*
* @since 2.1.1.23
*
* @param bool $field_ssl True to allow override if needed or false if not.
* @param string $file_url The file URL in question.
* @param GF_Field_FileUpload $field The field object for further context.
*/
$field_ssl = apply_filters( 'gform_secure_file_download_is_https', true, $file_url, $this );
if ( GFCommon::is_ssl() && strpos( $file_url, 'http:' ) !== false && $field_ssl === true ) {
$file_url = str_replace( 'http:', 'https:', $file_url );
}
$download_file_text = esc_attr__( 'Download file', 'gravityforms' );
$delete_file_text = esc_attr__( 'Delete file', 'gravityforms' );
$view_file_text = esc_attr__( 'View file', 'gravityforms' );
$file_index = intval( $file_index );
$file_url = esc_attr( $file_url );
$display_file_url = GFCommon::truncate_url( $file_url );
$file_url = $this->get_download_url( $file_url );
$download_button_url = GFCommon::get_base_url() . '/images/download.png';
$delete_button_url = GFCommon::get_base_url() . '/images/delete.png';
$preview .= "<div id='preview_file_{$file_index}' class='ginput_preview'>
<a href='{$file_url}' target='_blank' aria-label='{$view_file_text}'>{$display_file_url}</a>
<a href='{$file_url}' target='_blank' aria-label='{$download_file_text}'>
<img src='{$download_button_url}' alt='' style='margin-left:10px;'/></a><a href='javascript:void(0);' aria-label='{$delete_file_text}' onclick='DeleteFile({$lead_id},{$id},this);' onkeypress='DeleteFile({$lead_id},{$id},this);' ><img src='{$delete_button_url}' alt='' style='margin-left:10px;'/></a>
</div>";
}
$preview .= '</div>';
return $preview;
} else {
$input_name = "input_{$id}";
$uploaded_files = isset( GFFormsModel::$uploaded_files[ $form_id ][ $input_name ] ) ? GFFormsModel::$uploaded_files[ $form_id ][ $input_name ] : array();
$file_infos = $multiple_files ? $uploaded_files : RGFormsModel::get_temp_filename( $form_id, $input_name );
if ( ! empty( $file_infos ) ) {
$preview = sprintf( "<div id='%s'>", $file_list_id );
$file_infos = $multiple_files ? $uploaded_files : array( $file_infos );
foreach ( $file_infos as $file_info ) {
$file_upload_markup = apply_filters( 'gform_file_upload_markup', "<img alt='" . esc_attr__( 'Delete file', 'gravityforms' ) . "' class='gform_delete' src='" . GFCommon::get_base_url() . "/images/delete.png' onclick='gformDeleteUploadedFile({$form_id}, {$id}, this);' onkeypress='gformDeleteUploadedFile({$form_id}, {$id}, this);' /> <strong>" . esc_html( $file_info['uploaded_filename'] ) . '</strong>', $file_info, $form_id, $id );
$preview .= "<div class='ginput_preview'>{$file_upload_markup}</div>";
}
$preview .= '</div>';
if ( ! $multiple_files ) {
$upload = str_replace( " class='", " class='gform_hidden ", $upload );
}
return "<div class='ginput_container ginput_container_fileupload'>" . $upload . " {$preview}</div>";
} else {
$preview = $multiple_files ? sprintf( "<div id='%s'></div>", $file_list_id ) : '';
return "<div class='ginput_container ginput_container_fileupload'>$upload</div>" . $preview;
}
}
}
public function is_value_submission_empty( $form_id ) {
$input_name = 'input_' . $this->id;
if ( $this->multipleFiles ) {
$uploaded_files = GFFormsModel::$uploaded_files[ $form_id ];
$file_info = rgar( $uploaded_files, $input_name );
return empty( $file_info );
} else {
$file_info = GFFormsModel::get_temp_filename( $form_id, $input_name );
return ! $file_info && empty( $_FILES[ $input_name ]['name'] );
}
}
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
if ( ! $this->multipleFiles ) {
return $this->get_single_file_value( $form['id'], $input_name );
}
if ( $this->is_entry_detail() && empty( $lead ) ) {
// Deleted files remain in the $value from $_POST so use the updated entry value.
$lead = GFFormsModel::get_lead( $lead_id );
$value = rgar( $lead, strval( $this->id ) );
}
return $this->get_multifile_value( $form['id'], $input_name, $value );
}
public function get_multifile_value( $form_id, $input_name, $value ) {
global $_gf_uploaded_files;
GFCommon::log_debug( __METHOD__ . '(): Starting.' );
if ( isset( $_gf_uploaded_files[ $input_name ] ) ) {
$value = $_gf_uploaded_files[ $input_name ];
} else {
if ( isset( GFFormsModel::$uploaded_files[ $form_id ][ $input_name ] ) ) {
$uploaded_temp_files = GFFormsModel::$uploaded_files[ $form_id ][ $input_name ];
$uploaded_files = array();
foreach ( $uploaded_temp_files as $i => $file_info ) {
$temp_filepath = GFFormsModel::get_upload_path( $form_id ) . '/tmp/' . wp_basename( $file_info['temp_filename'] );
if ( $file_info && file_exists( $temp_filepath ) ) {
$uploaded_files[ $i ] = $this->move_temp_file( $form_id, $file_info );
}
}
if ( ! empty( $value ) ) { // merge with existing files (admin edit entry)
$value = json_decode( $value, true );
$value = array_merge( $value, $uploaded_files );
$value = json_encode( $value );
} else {
$value = json_encode( $uploaded_files );
}
} else {
GFCommon::log_debug( __METHOD__ . '(): No files uploaded. Exiting.' );
$value = '';
}
$_gf_uploaded_files[ $input_name ] = $value;
}
$value_safe = $this->sanitize_entry_value( $value, $form_id );
return $value_safe;
}
public function get_single_file_value( $form_id, $input_name ) {
global $_gf_uploaded_files;
GFCommon::log_debug( __METHOD__ . '(): Starting.' );
if ( empty( $_gf_uploaded_files ) ) {
$_gf_uploaded_files = array();
}
if ( ! isset( $_gf_uploaded_files[ $input_name ] ) ) {
//check if file has already been uploaded by previous step
$file_info = GFFormsModel::get_temp_filename( $form_id, $input_name );
$temp_filename = rgar( $file_info, 'temp_filename', '' );
$temp_filepath = GFFormsModel::get_upload_path( $form_id ) . '/tmp/' . $temp_filename;
if ( $file_info && file_exists( $temp_filepath ) ) {
GFCommon::log_debug( __METHOD__ . '(): File already uploaded to tmp folder, moving.' );
$_gf_uploaded_files[ $input_name ] = $this->move_temp_file( $form_id, $file_info );
} else if ( ! empty( $_FILES[ $input_name ]['name'] ) ) {
GFCommon::log_debug( __METHOD__ . '(): calling upload_file' );
$_gf_uploaded_files[ $input_name ] = $this->upload_file( $form_id, $_FILES[ $input_name ] );
} else {
GFCommon::log_debug( __METHOD__ . '(): No file uploaded. Exiting.' );
}
}
return rgget( $input_name, $_gf_uploaded_files );
}
public function upload_file( $form_id, $file ) {
GFCommon::log_debug( __METHOD__ . '(): Uploading file: ' . $file['name'] );
$target = GFFormsModel::get_file_upload_path( $form_id, $file['name'] );
if ( ! $target ) {
GFCommon::log_debug( __METHOD__ . '(): FAILED (Upload folder could not be created.)' );
return 'FAILED (Upload folder could not be created.)';
}
GFCommon::log_debug( __METHOD__ . '(): Upload folder is ' . print_r( $target, true ) );
if ( move_uploaded_file( $file['tmp_name'], $target['path'] ) ) {
GFCommon::log_debug( __METHOD__ . '(): File ' . $file['tmp_name'] . ' successfully moved to ' . $target['path'] . '.' );
$this->set_permissions( $target['path'] );
return $target['url'];
} else {
GFCommon::log_debug( __METHOD__ . '(): FAILED (Temporary file ' . $file['tmp_name'] . ' could not be copied to ' . $target['path'] . '.)' );
return 'FAILED (Temporary file could not be copied.)';
}
}
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
if ( $this->multipleFiles ) {
$uploaded_files_arr = empty( $value ) ? array() : json_decode( $value, true );
$file_count = count( $uploaded_files_arr );
if ( $file_count > 1 ) {
$value = empty( $uploaded_files_arr ) ? '' : sprintf( esc_html__( '%d files', 'gravityforms' ), count( $uploaded_files_arr ) );
return $value;
} elseif ( $file_count == 1 ) {
$value = current( $uploaded_files_arr );
} elseif ( $file_count == 0 ) {
return;
}
}
$file_path = $value;
if ( ! empty( $file_path ) ) {
//displaying thumbnail (if file is an image) or an icon based on the extension
$thumb = GFEntryList::get_icon_url( $file_path );
$file_path = $this->get_download_url( $file_path );
$file_path = esc_attr( $file_path );
$value = "<a href='$file_path' target='_blank' aria-label='" . esc_attr__( 'View the image', 'gravityforms' ) . "'><img src='$thumb' alt='' /></a>";
}
return $value;
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
$output = '';
if ( ! empty( $value ) ) {
$output_arr = array();
$file_paths = $this->multipleFiles ? json_decode( $value ) : array( $value );
$force_download = in_array( 'download', $this->get_modifiers() );
if ( is_array( $file_paths ) ) {
foreach ( $file_paths as $file_path ) {
$basename = wp_basename( $file_path );
$file_path = $this->get_download_url( $file_path, $force_download );
/**
* Allow for override of SSL replacement
*
* By default Gravity Forms will attempt to determine if the schema of the URL should be overwritten for SSL.
* This is not ideal for all situations, particularly domain mapping. Setting $field_ssl to false will prevent
* the override.
*
* @since 2.1.1.23
*
* @param bool $field_ssl True to allow override if needed or false if not.
* @param string $file_path The file path of the download file.
* @param GF_Field_FileUpload $field The field object for further context.
*/
$field_ssl = apply_filters( 'gform_secure_file_download_is_https', true, $file_path, $this );
if ( GFCommon::is_ssl() && strpos( $file_path, 'http:' ) !== false && $field_ssl === true ) {
$file_path = str_replace( 'http:', 'https:', $file_path );
}
/**
* Allows for the filtering of the file path before output.
*
* @since 2.1.1.23
*
* @param string $file_path The file path of the download file.
* @param GF_Field_FileUpload $field The field object for further context.
*/
$file_path = str_replace( ' ', '%20', apply_filters( 'gform_fileupload_entry_value_file_path', $file_path, $this ) );
$output_arr[] = $format == 'text' ? $file_path : sprintf( "<li><a href='%s' target='_blank' aria-label='%s'>%s</a></li>", esc_attr( $file_path ), esc_attr__( 'Click to view', 'gravityforms' ), $basename );
}
$output = join( PHP_EOL, $output_arr );
}
}
$output = empty( $output ) || $format == 'text' ? $output : sprintf( '<ul>%s</ul>', $output );
return $output;
}
/**
* Gets merge tag values.
*
* @since Unknown
* @access public
*
* @uses GF_Field::get_modifiers()
* @uses GF_Field_FileUpload::get_download_url()
*
* @param array|string $value The value of the input.
* @param string $input_id The input ID to use.
* @param array $entry The Entry Object.
* @param array $form The Form Object
* @param string $modifier The modifier passed.
* @param array|string $raw_value The raw value of the input.
* @param bool $url_encode If the result should be URL encoded.
* @param bool $esc_html If the HTML should be escaped.
* @param string $format The format that the value should be.
* @param bool $nl2br If the nl2br function should be used.
*
* @return string The processed merge tag.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
$force_download = in_array( 'download', $this->get_modifiers() );
if ( $this->multipleFiles ) {
$files = empty( $raw_value ) ? array() : json_decode( $raw_value, true );
foreach ( $files as &$file ) {
$file = $this->get_download_url( $file, $force_download );
$file = str_replace( ' ', '%20', $file );
if ( $esc_html ) {
$value = esc_html( $value );
}
}
$value = $format == 'html' ? join( '<br />', $files ) : join( ', ', $files );
} else {
$value = $this->get_download_url( $value, $force_download );
$value = str_replace( ' ', '%20', $value );
}
if ( $url_encode ) {
$value = urlencode( $value );
}
return $value;
}
public function move_temp_file( $form_id, $tempfile_info ) {
$target = GFFormsModel::get_file_upload_path( $form_id, $tempfile_info['uploaded_filename'] );
$source = GFFormsModel::get_upload_path( $form_id ) . '/tmp/' . wp_basename( $tempfile_info['temp_filename'] );
GFCommon::log_debug( __METHOD__ . '(): Moving temp file from: ' . $source );
if ( rename( $source, $target['path'] ) ) {
GFCommon::log_debug( __METHOD__ . '(): File successfully moved.' );
$this->set_permissions( $target['path'] );
return $target['url'];
} else {
GFCommon::log_debug( __METHOD__ . '(): FAILED (Temporary file could not be moved.)' );
return 'FAILED (Temporary file could not be moved.)';
}
}
function set_permissions( $path ) {
GFCommon::log_debug( __METHOD__ . '(): Setting permissions on: ' . $path );
GFFormsModel::set_permissions( $path );
}
public function sanitize_settings() {
parent::sanitize_settings();
if ( $this->maxFileSize ) {
$this->maxFileSize = absint( $this->maxFileSize );
}
if ( $this->maxFiles ) {
$this->maxFiles = preg_replace( '/[^0-9,.]/', '', $this->maxFiles );
}
$this->multipleFiles = (bool) $this->multipleFiles;
$this->allowedExtensions = sanitize_text_field( $this->allowedExtensions );
}
public function get_value_export( $entry, $input_id = '', $use_text = false, $is_csv = false ) {
if ( empty( $input_id ) ) {
$input_id = $this->id;
}
$value = rgar( $entry, $input_id );
if ( $this->multipleFiles && ! empty( $value ) ) {
return implode( ' , ', json_decode( $value, true ) );
}
return $value;
}
/**
* Returns the download URL for a file. The URL is not escaped for output.
*
* @since 2.0
* @access public
*
* @param string $file The complete file URL.
* @param bool $force_download If the download should be forced. Defaults to false.
*
* @return string
*/
public function get_download_url( $file, $force_download = false ) {
$download_url = $file;
$secure_download_location = true;
/**
* By default the real location of the uploaded file will be hidden and the download URL will be generated with
* a security token to prevent guessing or enumeration attacks to discover the location of other files.
*
* Return FALSE to display the real location.
*
* @param bool $secure_download_location If the secure location should be used. Defaults to true.
* @param string $file The URL of the file.
* @param GF_Field_FileUpload $this The Field
*/
$secure_download_location = apply_filters( 'gform_secure_file_download_location', $secure_download_location, $file, $this );
$secure_download_location = apply_filters( 'gform_secure_file_download_location_' . $this->formId, $secure_download_location, $file, $this );
if ( ! $secure_download_location ) {
/**
* Allow filtering of the download URL.
*
* Allows for manual filtering of the download URL to handle conditions such as
* unusual domain mapping and others.
*
* @since 2.1.1.1
*
* @param string $download_url The URL from which to download the file.
* @param GF_Field_FileUpload $field The field object for further context.
*/
return apply_filters( 'gform_secure_file_download_url', $download_url, $this );
}
$upload_root = GFFormsModel::get_upload_url( $this->formId );
$upload_root = trailingslashit( $upload_root );
// Only hide the real URL if the location of the file is in the upload root for the form.
// The upload root is calculated using the WP Salts so if the WP Salts have changed then file can't be located during the download request.
if ( strpos( $file, $upload_root ) !== false ) {
$file = str_replace( $upload_root, '', $file );
$download_url = site_url( 'index.php' );
$args = array(
'gf-download' => urlencode( $file ),
'form-id' => $this->formId,
'field-id' => $this->id,
'hash' => GFCommon::generate_download_hash( $this->formId, $this->id, $file ),
);
if ( $force_download ) {
$args['dl'] = 1;
}
$download_url = add_query_arg( $args, $download_url );
}
/**
* Allow filtering of the download URL.
*
* Allows for manual filtering of the download URL to handle conditions such as
* unusual domain mapping and others.
*
* @param string $download_url The URL from which to download the file.
* @param GF_Field_FileUpload $field The field object for further context.
*/
return apply_filters( 'gform_secure_file_download_url', $download_url, $this );
}
}
GF_Fields::register( new GF_Field_FileUpload() );
class-gf-field-date.php 0000666 00000106553 15126403614 0010770 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Date extends GF_Field {
public $type = 'date';
public function get_form_editor_field_title() {
return esc_attr__( 'Date', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'sub_label_placement_setting',
'admin_label_setting',
'rules_setting',
'date_input_type_setting',
'visibility_setting',
'duplicate_setting',
'date_format_setting',
'default_value_setting',
'placeholder_setting',
'description_setting',
'css_class_setting',
);
}
/**
* Whether this field expects an array during submission.
*
* @since 2.4
*
* @return bool
*/
public function is_value_submission_array() {
return in_array( $this->dateType, array( 'datefield', 'datedropdown' ) );
}
public function validate( $value, $form ) {
if ( is_array( $value ) && rgempty( 0, $value ) && rgempty( 1, $value ) && rgempty( 2, $value ) ) {
$value = null;
}
if ( ! empty( $value ) ) {
$format = empty( $this->dateFormat ) ? 'mdy' : $this->dateFormat;
$date = GFCommon::parse_date( $value, $format );
if ( empty( $date ) || ! $this->checkdate( $date['month'], $date['day'], $date['year'] ) ) {
$this->failed_validation = true;
$format_name = '';
switch ( $format ) {
case 'mdy' :
$format_name = 'mm/dd/yyyy';
break;
case 'dmy' :
$format_name = 'dd/mm/yyyy';
break;
case 'dmy_dash' :
$format_name = 'dd-mm-yyyy';
break;
case 'dmy_dot' :
$format_name = 'dd.mm.yyyy';
break;
case 'ymd_slash' :
$format_name = 'yyyy/mm/dd';
break;
case 'ymd_dash' :
$format_name = 'yyyy-mm-dd';
break;
case 'ymd_dot' :
$format_name = 'yyyy.mm.dd';
break;
}
$message = $this->dateType == 'datepicker' ? sprintf( esc_html__( 'Please enter a valid date in the format (%s).', 'gravityforms' ), $format_name ) : esc_html__( 'Please enter a valid date.', 'gravityforms' );
$this->validation_message = empty( $this->errorMessage ) ? $message : $this->errorMessage;
}
}
}
public function is_value_submission_empty( $form_id ) {
$value = rgpost( 'input_' . $this->id );
if ( is_array( $value ) ) {
// Date field and date drop-downs
foreach ( $value as $input ) {
if ( strlen( trim( $input ) ) <= 0 ) {
return true;
}
}
return false;
} else {
// Date picker
return strlen( trim( $value ) ) <= 0;
}
}
public function get_field_input( $form, $value = '', $entry = null ) {
$picker_value = '';
if ( is_array( $value ) ) {
// GFCommon::parse_date() takes a numeric array.
$value = array_values( $value );
} else {
$picker_value = esc_attr( $value );
}
$format = empty( $this->dateFormat ) ? 'mdy' : esc_attr( $this->dateFormat );
$date_info = GFCommon::parse_date( $value, $format );
$day_value = esc_attr( rgget( 'day', $date_info ) );
$month_value = esc_attr( rgget( 'month', $date_info ) );
$year_value = esc_attr( rgget( 'year', $date_info ) );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$form_id = $form['id'];
$id = intval( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$size = $this->size;
$disabled_text = $is_form_editor ? "disabled='disabled'" : '';
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$class = esc_attr( $class );
$form_sub_label_placement = rgar( $form, 'subLabelPlacement' );
$field_sub_label_placement = $this->subLabelPlacement;
$is_sub_label_above = $field_sub_label_placement == 'above' || ( empty( $field_sub_label_placement ) && $form_sub_label_placement == 'above' );
$sub_label_class_attribute = $field_sub_label_placement == 'hidden_label' ? "class='hidden_sub_label screen-reader-text'" : '';
$month_input = GFFormsModel::get_input( $this, $this->id . '.1' );
$day_input = GFFormsModel::get_input( $this, $this->id . '.2' );
$year_input = GFFormsModel::get_input( $this, $this->id . '.3' );
$month_sub_label = rgar( $month_input, 'customLabel' ) != '' ? $month_input['customLabel'] : esc_html( _x( 'MM', 'Abbreviation: Month', 'gravityforms' ) );
$day_sub_label = rgar( $day_input, 'customLabel' ) != '' ? $day_input['customLabel'] : esc_html__( 'DD', 'gravityforms' );
$year_sub_label = rgar( $year_input, 'customLabel' ) != '' ? $year_input['customLabel'] : esc_html__( 'YYYY', 'gravityforms' );
$month_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $month_input );
$day_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $day_input );
$year_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $year_input );
$month_placeholder_value = GFCommon::get_input_placeholder_value( $month_input );
$day_placeholder_value = GFCommon::get_input_placeholder_value( $day_input );
$year_placeholder_value = GFCommon::get_input_placeholder_value( $year_input );
$date_picker_placeholder = $this->get_field_placeholder_attribute();
$is_html5 = RGFormsModel::is_html5_enabled();
$date_input_type = $is_html5 ? 'number' : 'text';
$month_html5_attributes = $is_html5 ? "min='1' max='12' step='1'" : '';
$day_html5_attributes = $is_html5 ? "min='1' max='31' step='1'" : '';
$year_min = apply_filters( 'gform_date_min_year', '1920', $form, $this );
$year_max = apply_filters( 'gform_date_max_year', date( 'Y' ) + 1, $form, $this );
$year_min_attribute = $is_html5 && is_numeric( $year_min ) ? "min='{$year_min}'" : '';
$year_max_attribute = $is_html5 && is_numeric( $year_max ) ? "max='{$year_max}'" : '';
$year_step_attribute = $is_html5 ? "step='1'" : '';
$field_position = substr( $format, 0, 3 );
if ( $is_form_editor ) {
$datepicker_display = in_array( $this->dateType, array( 'datefield', 'datedropdown' ) ) ? 'none' : 'inline';
$datefield_display = $this->dateType == 'datefield' ? 'inline' : 'none';
$dropdown_display = $this->dateType == 'datedropdown' ? 'inline' : 'none';
$icon_display = $this->calendarIconType == 'calendar' ? 'inline' : 'none';
if ( $is_sub_label_above ) {
$month_field = "<div class='gfield_date_month ginput_date' id='gfield_input_date_month' style='display:$datefield_display'>
<label for='{$field_id}_1' {$sub_label_class_attribute}>{$month_sub_label}</label>
<input id='{$field_id}_1' name='ginput_month' type='text' {$month_placeholder_attribute} {$disabled_text} value='{$month_value}'/>
</div>";
$day_field = "<div class='gfield_date_day ginput_date' id='gfield_input_date_day' style='display:$datefield_display'>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$day_sub_label}</label>
<input id='{$field_id}_2' name='ginput_day' type='text' {$day_placeholder_attribute} {$disabled_text} value='{$day_value}'/>
</div>";
$year_field = "<div class='gfield_date_year ginput_date' id='gfield_input_date_year' style='display:$datefield_display'>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$year_sub_label}</label>
<input id='{$field_id}_3' type='text' name='text' {$year_placeholder_attribute} {$disabled_text} value='{$year_value}'/>
</div>";
} else {
$month_field = "<div class='gfield_date_month ginput_date' id='gfield_input_date_month' style='display:$datefield_display'>
<input id='{$field_id}_1' name='ginput_month' type='text' {$month_placeholder_attribute} {$disabled_text} value='{$month_value}'/>
<label for='{$field_id}_1' {$sub_label_class_attribute}>{$month_sub_label}</label>
</div>";
$day_field = "<div class='gfield_date_day ginput_date' id='gfield_input_date_day' style='display:$datefield_display'>
<input id='{$field_id}_2' name='ginput_day' type='text' {$day_placeholder_attribute} {$disabled_text} value='{$day_value}'/>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$day_sub_label}</label>
</div>";
$year_field = "<div class='gfield_date_year ginput_date' id='gfield_input_date_year' style='display:$datefield_display'>
<input type='text' id='{$field_id}_3' name='ginput_year' {$year_placeholder_attribute} {$disabled_text} value='{$year_value}'/>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$year_sub_label}</label>
</div>";
}
$month_dropdown = "<div class='gfield_date_dropdown_month ginput_date_dropdown' id='gfield_dropdown_date_month' style='display:$dropdown_display'>" . $this->get_month_dropdown( '', "{$field_id}_1", rgar( $date_info, 'month' ), '', $disabled_text, $month_placeholder_value ) . '</div>';
$day_dropdown = "<div class='gfield_date_dropdown_day ginput_date_dropdown' id='gfield_dropdown_date_day' style='display:$dropdown_display'>" . $this->get_day_dropdown( '', "{$field_id}_2", rgar( $date_info, 'day' ), '', $disabled_text, $day_placeholder_value ) . '</div>';
$year_dropdown = "<div class='gfield_date_dropdown_year ginput_date_dropdown' id='gfield_dropdown_date_year' style='display:$dropdown_display'>" . $this->get_year_dropdown( '', "{$field_id}_3", rgar( $date_info, 'year' ), '', $disabled_text, $year_placeholder_value, $form ) . '</div>';
$field_string = "<div class='ginput_container ginput_container_date' id='gfield_input_datepicker' style='display:$datepicker_display'><input name='ginput_datepicker' type='text' {$date_picker_placeholder} {$disabled_text} value='{$picker_value}'/><img src='" . GFCommon::get_base_url() . "/images/calendar.png' id='gfield_input_datepicker_icon' style='display:$icon_display'/></div>";
switch ( $field_position ) {
case 'dmy' :
$date_inputs = $day_field . $month_field . $year_field . $day_dropdown . $month_dropdown . $year_dropdown;
break;
case 'ymd' :
$date_inputs = $year_field . $month_field . $day_field . $year_dropdown . $month_dropdown . $day_dropdown;
break;
default :
$date_inputs = $month_field . $day_field . $year_field . $month_dropdown . $day_dropdown . $year_dropdown;
break;
}
$field_string .= "<div id='{$field_id}' class='ginput_container ginput_container_date'>{$date_inputs}</div>";
return $field_string;
} else {
$date_type = $this->dateType;
if ( in_array( $date_type, array( 'datefield', 'datedropdown' ) ) ) {
switch ( $field_position ) {
case 'dmy' :
$tabindex = $this->get_tabindex();
if ( $date_type == 'datedropdown' ) {
$field_str = "<div class='clear-multi'><div class='gfield_date_dropdown_day ginput_container ginput_container_date' id='{$field_id}_2_container'>" . $this->get_day_dropdown( "input_{$id}[]", "{$field_id}_2", rgar( $date_info, 'day' ), $tabindex, $disabled_text, $day_placeholder_value ) . '</div>';
$tabindex = $this->get_tabindex();
$field_str .= "<div class='gfield_date_dropdown_month ginput_container ginput_container_date' id='{$field_id}_1_container'>" . $this->get_month_dropdown( "input_{$id}[]", "{$field_id}_1", rgar( $date_info, 'month' ), $tabindex, $disabled_text, $month_placeholder_value ) . '</div>';
$tabindex = $this->get_tabindex();
$field_str .= "<div class='gfield_date_dropdown_year ginput_container ginput_container_date' id='{$field_id}_3_container'>" . $this->get_year_dropdown( "input_{$id}[]", "{$field_id}_3", rgar( $date_info, 'year' ), $tabindex, $disabled_text, $year_placeholder_value, $form ) . '</div></div>';
} else {
$field_str = $is_sub_label_above
? "<div class='clear-multi'>
<div class='gfield_date_day ginput_container ginput_container_date' id='{$field_id}_2_container'>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$day_sub_label}</label>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_2' value='$day_value' {$tabindex} {$disabled_text} {$day_placeholder_attribute} {$day_html5_attributes}/>
</div>"
: "<div class='clear-multi'>
<div class='gfield_date_day ginput_container ginput_container_date' id='{$field_id}_2_container'>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_2' value='$day_value' {$tabindex} {$disabled_text} {$day_placeholder_attribute} {$day_html5_attributes}/>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$day_sub_label}</label>
</div>";
$tabindex = $this->get_tabindex();
$field_str .= $is_sub_label_above
? "<div class='gfield_date_month ginput_container ginput_container_date' id='{$field_id}_1_container'>
<label for='{$field_id}_1' {$sub_label_class_attribute}>{$month_sub_label}</label>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_1' value='{$month_value}' {$tabindex} {$disabled_text} {$month_placeholder_attribute} {$month_html5_attributes}/>
</div>"
: "<div class='gfield_date_month ginput_container ginput_container_date' id='{$field_id}_1_container'>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_1' value='{$month_value}' {$tabindex} {$disabled_text} {$month_placeholder_attribute} {$month_html5_attributes}/>
<label for='{$field_id}_1' {$sub_label_class_attribute}>{$month_sub_label}</label>
</div>";
$tabindex = $this->get_tabindex();
$field_str .= $is_sub_label_above
? "<div class='gfield_date_year ginput_container ginput_container_date' id='{$field_id}_3_container'>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$year_sub_label}</label>
<input type='{$date_input_type}' maxlength='4' name='input_{$id}[]' id='{$field_id}_3' value='{$year_value}' {$tabindex} {$disabled_text} {$year_placeholder_attribute} {$year_min_attribute} {$year_max_attribute} {$year_step_attribute}/>
</div>
</div>"
: "<div class='gfield_date_year ginput_container ginput_container_date' id='{$field_id}_3_container'>
<input type='{$date_input_type}' maxlength='4' name='input_{$id}[]' id='{$field_id}_3' value='{$year_value}' {$tabindex} {$disabled_text} {$year_placeholder_attribute} {$year_min_attribute} {$year_max_attribute} {$year_step_attribute}/>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$year_sub_label}</label>
</div>
</div>";
}
break;
case 'ymd' :
$tabindex = $this->get_tabindex();
if ( $date_type == 'datedropdown' ) {
$field_str = "<div class='clear-multi'><div class='gfield_date_dropdown_year ginput_container ginput_container_date' id='{$field_id}_3_container'>" . $this->get_year_dropdown( "input_{$id}[]", "{$field_id}_3", rgar( $date_info, 'year' ), $tabindex, $disabled_text, $year_placeholder_value, $form ) . '</div>';
$tabindex = $this->get_tabindex();
$field_str .= "<div class='gfield_date_dropdown_month ginput_container ginput_container_date' id='{$field_id}_1_container'>" . $this->get_month_dropdown( "input_{$id}[]", "{$field_id}_1", rgar( $date_info, 'month' ), $tabindex, $disabled_text, $month_placeholder_value ) . '</div>';
$tabindex = $this->get_tabindex();
$field_str .= "<div class='gfield_date_dropdown_day ginput_container ginput_container_date' id='{$field_id}_2_container'>" . $this->get_day_dropdown( "input_{$id}[]", "{$field_id}_2", rgar( $date_info, 'day' ), $tabindex, $disabled_text, $day_placeholder_value ) . '</div></div>';
} else {
$field_str = $is_sub_label_above
? "<div class='clear-multi'>
<div class='gfield_date_year ginput_container ginput_container_date' id='{$field_id}_3_container'>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$year_sub_label}</label>
<input type='{$date_input_type}' maxlength='4' name='input_{$id}[]' id='{$field_id}_3' value='{$year_value}' {$tabindex} {$disabled_text} {$year_placeholder_attribute} {$year_min_attribute} {$year_max_attribute} {$year_step_attribute}/>
</div>"
: "<div class='clear-multi'>
<div class='gfield_date_year ginput_container ginput_container_date' id='{$field_id}_3_container'>
<input type='{$date_input_type}' maxlength='4' name='input_{$id}[]' id='{$field_id}_3' value='{$year_value}' {$tabindex} {$disabled_text} {$year_placeholder_attribute} {$year_min_attribute} {$year_max_attribute} {$year_step_attribute}/>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$year_sub_label}</label>
</div>";
$tabindex = $this->get_tabindex();
$field_str .= $is_sub_label_above
? "<div class='gfield_date_month ginput_container ginput_container_date' id='{$field_id}_1_container'>
<label for='{$field_id}_1' {$sub_label_class_attribute}>{$month_sub_label}</label>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_1' value='{$month_value}' {$tabindex} {$disabled_text} {$month_placeholder_attribute} {$month_html5_attributes}/>
</div>"
: "<div class='gfield_date_month ginput_container ginput_container_date' id='{$field_id}_1_container'>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_1' value='{$month_value}' {$tabindex} {$disabled_text} {$month_placeholder_attribute} {$month_html5_attributes}/>
<label for='{$field_id}_1' {$sub_label_class_attribute}>{$month_sub_label}</label>
</div>";
$tabindex = $this->get_tabindex();
$field_str .= $is_sub_label_above
? "<div class='gfield_date_day ginput_container ginput_container_date' id='{$field_id}_2_container'>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$day_sub_label}</label>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_2' value='{$day_value}' {$tabindex} {$disabled_text} {$day_placeholder_attribute} {$day_html5_attributes}/>
</div>
</div>"
: "<div class='gfield_date_day ginput_container ginput_container_date' id='{$field_id}_2_container'>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_2' value='{$day_value}' {$tabindex} {$disabled_text} {$day_placeholder_attribute} {$day_html5_attributes}/>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$day_sub_label}</label>
</div>
</div>";
}
break;
default :
$tabindex = $this->get_tabindex();
if ( $date_type == 'datedropdown' ) {
$field_str = "<div class='clear-multi'><div class='gfield_date_dropdown_month ginput_container ginput_container_date' id='{$field_id}_1_container'>" . $this->get_month_dropdown( "input_{$id}[]", "{$field_id}_1", rgar( $date_info, 'month' ), $tabindex, $disabled_text, $month_placeholder_value ) . '</div>';
$tabindex = $this->get_tabindex();
$field_str .= "<div class='gfield_date_dropdown_day ginput_container ginput_container_date' id='{$field_id}_2_container'>" . $this->get_day_dropdown( "input_{$id}[]", "{$field_id}_2", rgar( $date_info, 'day' ), $tabindex, $disabled_text, $day_placeholder_value ) . '</div>';
$tabindex = $this->get_tabindex();
$field_str .= "<div class='gfield_date_dropdown_year ginput_container ginput_container_date' id='{$field_id}_3_container'>" . $this->get_year_dropdown( "input_{$id}[]", "{$field_id}_3", rgar( $date_info, 'year' ), $tabindex, $disabled_text, $year_placeholder_value, $form ) . '</div></div>';
} else {
$field_str = $is_sub_label_above
? "<div class='clear-multi'><div class='gfield_date_month ginput_container ginput_container_date' id='{$field_id}_1_container'>
<label for='{$field_id}_1' {$sub_label_class_attribute}>{$month_sub_label}</label>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_1' value='{$month_value}' {$tabindex} {$disabled_text} {$month_placeholder_attribute} {$month_html5_attributes}/>
</div>"
: "<div class='clear-multi'><div class='gfield_date_month ginput_container ginput_container_date' id='{$field_id}_1_container'>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_1' value='{$month_value}' {$tabindex} {$disabled_text} {$month_placeholder_attribute} {$month_html5_attributes}/>
<label for='{$field_id}_1' {$sub_label_class_attribute}>{$month_sub_label}</label>
</div>";
$tabindex = $this->get_tabindex();
$field_str .= $is_sub_label_above
? "<div class='gfield_date_day ginput_container ginput_container_date' id='{$field_id}_2_container'>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$day_sub_label}</label>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_2' value='{$day_value}' {$tabindex} {$disabled_text} {$day_placeholder_attribute} {$day_html5_attributes}/>
</div>"
: "<div class='gfield_date_day ginput_container ginput_container_date' id='{$field_id}_2_container'>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_2' value='{$day_value}' {$tabindex} {$disabled_text} {$day_placeholder_attribute} {$day_html5_attributes}/>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$day_sub_label}</label>
</div>";
$tabindex = $this->get_tabindex();
$field_str .= $is_sub_label_above
? "<div class='gfield_date_year ginput_container ginput_container_date' id='{$field_id}_3_container'>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$year_sub_label}</label>
<input type='{$date_input_type}' maxlength='4' name='input_{$id}[]' id='{$field_id}_3' value='{$year_value}' {$tabindex} {$disabled_text} {$year_placeholder_attribute} {$year_min_attribute} {$year_max_attribute} {$year_step_attribute}/>
</div>
</div>"
: "<div class='gfield_date_year ginput_container ginput_container_date' id='{$field_id}_3_container'>
<input type='{$date_input_type}' maxlength='4' name='input_{$id}[]' id='{$field_id}_3' value='{$year_value}' {$tabindex} {$disabled_text} {$year_placeholder_attribute} {$year_min_attribute} {$year_max_attribute} {$year_step_attribute}/>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$year_sub_label}</label>
</div>
</div>";
}
break;
}
return "<div id='{$field_id}' class='ginput_container ginput_container_date'>$field_str</div>";
} else {
$picker_value = esc_attr( GFCommon::date_display( $picker_value, $format ) );
$icon_class = $this->calendarIconType == 'none' ? 'datepicker_no_icon' : 'datepicker_with_icon';
$icon_url = empty( $this->calendarIconUrl ) ? GFCommon::get_base_url() . '/images/calendar.png' : $this->calendarIconUrl;
$icon_url = esc_url( $icon_url );
$tabindex = $this->get_tabindex();
$class = esc_attr( $class );
$aria_describedby = "aria-describedby='{$field_id}_date_format'";
$date_format_label = esc_attr__( 'Date Format: ', 'gravityforms' );
switch ( $format ) {
case 'mdy':
$date_format_label .= esc_attr__( 'MM slash DD slash YYYY', 'gravityforms' );
break;
case 'dmy':
$date_format_label .= esc_attr__( 'DD slash MM slash YYYY', 'gravityforms' );
break;
case 'dmy_dash':
$date_format_label .= esc_attr__( 'DD dash MM dash YYYY', 'gravityforms' );
break;
case 'dmy_dot':
$date_format_label .= esc_attr__( 'DD dot MM dot YYYY', 'gravityforms' );
break;
case 'ymd_slash':
$date_format_label .= esc_attr__( 'YYYY slash MM slash DD', 'gravityforms' );
break;
case 'ymd_dash':
$date_format_label .= esc_attr__( 'YYYY dash MM dash DD', 'gravityforms' );
break;
case 'ymd_dot':
$date_format_label .= esc_attr__( 'YYYY dot MM dot DD', 'gravityforms' );
break;
}
return "<div class='ginput_container ginput_container_date'>
<input name='input_{$id}' id='{$field_id}' type='text' value='{$picker_value}' class='datepicker {$class} {$format} {$icon_class}' {$tabindex} {$disabled_text} {$date_picker_placeholder} {$aria_describedby} />
<span id='{$field_id}_date_format' class='screen-reader-text'>{$date_format_label}</span>
</div>
<input type='hidden' id='gforms_calendar_icon_$field_id' class='gform_hidden' value='$icon_url'/>";
}
}
}
public function get_field_label_class() {
return $this->dateType == 'datefield' ? 'gfield_label gfield_label_before_complex' : 'gfield_label';
}
public function get_value_default() {
$value = parent::get_value_default();
if ( is_array( $this->inputs ) ) {
$value = $this->get_date_array_by_format( $value );
}
return $value;
}
/**
* The default value for mulit-input date fields will always be an array in mdy order
* this code will alter the order of the values to the date format of the field
*/
public function get_date_array_by_format( $value ) {
$format = empty( $this->dateFormat ) ? 'mdy' : esc_attr( $this->dateFormat );
$position = substr( $format, 0, 3 );
$date = array_combine( array( 'm', 'd', 'y' ), $value ); // takes our numerical array and converts it to an associative array
$value = array_merge( array_flip( str_split( $position ) ), $date ); // uses the mdy position as the array keys and creates a new array in the desired order
return $value;
}
public function checkdate( $month, $day, $year ) {
if ( empty( $month ) || ! is_numeric( $month ) || empty( $day ) || ! is_numeric( $day ) || empty( $year ) || ! is_numeric( $year ) || strlen( $year ) != 4 ) {
return false;
}
return checkdate( $month, $day, $year );
}
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
return GFCommon::date_display( $value, $this->dateFormat );
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
return GFCommon::date_display( $value, $this->dateFormat, $this->get_output_date_format() );
}
/**
* Gets merge tag values.
*
* @since Unknown
* @access public
*
* @uses GFCommon::date_display()
* @uses GF_Field_Date::$dateFormat
*
* @param array|string $value The value of the input.
* @param string $input_id The input ID to use.
* @param array $entry The Entry Object.
* @param array $form The Form Object
* @param string $modifier The modifier passed.
* @param array|string $raw_value The raw value of the input.
* @param bool $url_encode If the result should be URL encoded.
* @param bool $esc_html If the HTML should be escaped.
* @param string $format The format that the value should be.
* @param bool $nl2br If the nl2br function should be used.
*
* @return string The processed merge tag.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
return GFCommon::date_display( $value, $this->dateFormat, $this->get_output_date_format() );
}
/**
* Returns the date format to use when outputting the entry value on the detail page and when merge tags are processed.
*
* @since 2.4
*
* @return string
*/
public function get_output_date_format() {
$modifiers = $this->get_modifiers();
if ( ! empty( $modifiers ) ) {
$valid_modifiers = array(
'year',
'month',
'day',
'ymd',
'ymd_dash',
'ymd_dot',
'ymd_slash',
'mdy',
'mdy_dash',
'mdy_dot',
'mdy_slash',
'dmy',
'dmy_dash',
'dmy_dot',
'dmy_slash',
);
foreach ( $modifiers as $modifier ) {
if ( in_array( $modifier, $valid_modifiers ) ) {
return $modifier;
}
}
}
return $this->dateFormat;
}
/**
* Returns a JS script to be rendered in the front end of the form.
*
* @param array $form The Form Object
*
* @return string Returns a JS script to be processed in the front end.
*/
public function get_form_inline_script_on_page_render( $form ) {
//Only return merge tag script if form supports JS merge tags
if ( ! GFFormDisplay::has_js_merge_tag( $form ) ) {
return '';
}
return "gform.addFilter( 'gform_value_merge_tag_{$form['id']}_{$this->id}', function( value, input, modifier ) { if( modifier === 'label' ) { return false; } return input.length == 1 ? input.val() : jQuery(input[0]).val() + '/' + jQuery(input[1]).val() + '/' + jQuery(input[2]).val(); } );";
}
private function get_month_dropdown( $name = '', $id = '', $selected_value = '', $tabindex = '', $disabled_text = '', $placeholder = '' ) {
if ( $placeholder == '' ) {
$placeholder = esc_html__( 'Month', 'gravityforms' );
}
return $this->get_number_dropdown( $name, $id, $selected_value, $tabindex, $disabled_text, $placeholder, 1, 12 );
}
private function get_day_dropdown( $name = '', $id = '', $selected_value = '', $tabindex = '', $disabled_text = '', $placeholder = '' ) {
if ( $placeholder == '' ) {
$placeholder = esc_html__( 'Day', 'gravityforms' );
}
return $this->get_number_dropdown( $name, $id, $selected_value, $tabindex, $disabled_text, $placeholder, 1, 31 );
}
private function get_year_dropdown( $name, $id, $selected_value, $tabindex, $disabled_text, $placeholder, $form ) {
$name = ( is_string( $name ) ) ? $name : '';
$id = ( is_string( $id ) ) ? $id : '';
$selected_value = ( is_string( $selected_value ) ) ? $selected_value : '';
$tabindex = ( is_string( $tabindex ) ) ? $tabindex : '';
$disabled_text = ( is_string( $disabled_text ) ) ? $disabled_text : '';
$placeholder = ( is_string( $placeholder ) ) ? $placeholder : '';
if ( $placeholder == '' ) {
$placeholder = esc_html__( 'Year', 'gravityforms' );
}
$year_min = apply_filters( 'gform_date_min_year', '1920', $form, $this );
$year_max = apply_filters( 'gform_date_max_year', date( 'Y' ) + 1, $form, $this );
return $this->get_number_dropdown( $name, $id, $selected_value, $tabindex, $disabled_text, $placeholder, $year_max, $year_min );
}
private function get_number_dropdown( $name, $id, $selected_value, $tabindex, $disabled_text, $placeholder, $start_number, $end_number ) {
$str = "<select name='{$name}' id='{$id}' {$tabindex} {$disabled_text} aria-label='{$placeholder}'>";
if ( $placeholder !== false ) {
$str .= "<option value=''>{$placeholder}</option>";
}
$increment = $start_number < $end_number ? 1 : - 1;
for ( $i = $start_number; $i != ( $end_number + $increment ); $i += $increment ) {
$selected = intval( $i ) == intval( $selected_value ) ? "selected='selected'" : '';
$str .= "<option value='{$i}' {$selected}>{$i}</option>";
}
$str .= '</select>';
return $str;
}
/**
* Returns the value to save in the entry.
*
* @param string $value
* @param array $form
* @param string $input_name
* @param int $lead_id
* @param array $lead
*
* @return string
*/
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
// if $value is a default value and also an array, it will be an associative array; to be safe, let's convert all array $value to numeric
if ( is_array( $value ) ) {
$value = array_values( $value );
}
$value = GFFormsModel::prepare_date( $this->dateFormat, $value );
$value = $this->sanitize_entry_value( $value, $form['id'] );
return $value;
}
public function get_entry_inputs() {
return null;
}
public function sanitize_settings() {
parent::sanitize_settings();
$this->calendarIconType = wp_strip_all_tags( $this->calendarIconType );
$this->calendarIconUrl = wp_strip_all_tags( $this->calendarIconUrl );
if ( $this->dateFormat && ! in_array( $this->dateFormat, array( 'mdy', 'dmy', 'dmy_dash', 'dmy_dot', 'ymd_slash', 'ymd_dash', 'ymd_dot' ) ) ) {
$this->dateFormat = 'mdy';
}
}
/**
* Removes the "for" attribute in the field label. Inputs are only allowed one label (a11y) and the inputs already have labels.
*
* @since 2.4
* @access public
*
* @param array $form The Form Object currently being processed.
*
* @return string
*/
public function get_first_input_id( $form ) {
return in_array( $this->dateType, array( 'datefield', 'datedropdown' ) ) ? '' : parent::get_first_input_id( $form ) ;
}
// # FIELD FILTER UI HELPERS ---------------------------------------------------------------------------------------
/**
* Returns the filter settings for the current field.
*
* @since 2.4
*
* @return array
*/
public function get_filter_settings() {
$filter_settings = parent::get_filter_settings();
$filter_settings['placeholder'] = esc_html__( 'yyyy-mm-dd', 'gravityforms' );
$filter_settings['cssClass'] = 'datepicker ymd_dash';
return $filter_settings;
}
}
GF_Fields::register( new GF_Field_Date() );
class-gf-field-time.php 0000666 00000034241 15126403614 0011003 0 ustar 00 <?php
// If Gravity Forms isn't loaded, bail.
if ( ! class_exists( 'GFForms' ) ) {
die();
}
/**
* Class GF_Field_Time
*
* Handles Time fields.
*
* @since Unknown
* @uses GF_Field
*/
class GF_Field_Time extends GF_Field {
/**
* Sets the field type to be used in the field framework.
*
* @since Unknown
* @access public
*
* @var string $type The type of field this is.
*/
public $type = 'time';
/**
* Sets the title of the field to be used in the form editor.
*
* @since Unknown
* @access public
*
* @used-by GFCommon::get_field_type_title()
* @used-by GFAddOn::get_field_map_choices()
* @used-by GFAddOn::prepare_field_select_field()
* @used-by GFAddOn::settings_field_map_select()
* @used-by GF_Field::get_form_editor_button()
*
* @return string The field title.
*/
public function get_form_editor_field_title() {
return esc_attr__( 'Time', 'gravityforms' );
}
/**
* Defines the field editor settings that are available for this field.
*
* @since Unknown
* @access public
*
* @used-by GFFormDetail::inline_scripts()
*
* @return array Contains the settings available within the field editor.
*/
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'sub_labels_setting',
'label_placement_setting',
'sub_label_placement_setting',
'admin_label_setting',
'time_format_setting',
'rules_setting',
'visibility_setting',
'duplicate_setting',
'default_input_values_setting',
'input_placeholders_setting',
'description_setting',
'css_class_setting',
);
}
/**
* Validates the field inputs.
*
* @since Unknown
* @access public
*
* @used-by GFFormDisplay::validate()
* @uses GF_Field_Time::$failed_validation
* @uses GF_Field_Time::$validation_message
* @uses GF_Field_Time::$timeFormat
* @uses GF_Field_Time::$errorMessage
*
* @param array|string $value The field value or values to validate.
* @param array $form The Form Object.
*
* @return void
*/
public function validate( $value, $form ) {
// Create variable values if time came in one field.
if ( ! is_array( $value ) && ! empty( $value ) ) {
preg_match( '/^(\d*):(\d*) ?(.*)$/', $value, $matches );
$value = array();
$value[0] = $matches[1];
$value[1] = $matches[2];
}
$hour = rgar( $value, 0 );
$minute = rgar( $value, 1 );
if ( empty( $hour ) && empty( $minute ) ) {
return;
}
$is_valid_format = is_numeric( $hour ) && is_numeric( $minute );
$min_hour = $this->timeFormat == '24' ? 0 : 1;
$max_hour = $this->timeFormat == '24' ? 24 : 12;
$max_minute = $hour >= 24 ? 0 : 59;
if ( ! $is_valid_format || $hour < $min_hour || $hour > $max_hour || $minute < 0 || $minute > $max_minute ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'Please enter a valid time.', 'gravityforms' ) : $this->errorMessage;
}
}
/**
* Defines how the Time field input is shown.
*
* @since Unknown
* @access public
*
* @used-by GFCommon::get_field_input()
* @uses GF_Field::is_entry_detail()
* @uses GF_Field::is_form_editor()
* @uses GF_Field_Time::$subLabelPlacement
* @uses GFFormsModel::get_input()
* @uses GF_Field::get_input_placeholder_attribute()
* @uses GF_Field::get_tabindex()
* @uses GFFormsModel::is_html5_enabled()
*
* @param array $form The Form Object.
* @param string $value The field default value. Defaults to empty string.
* @param array|null $entry The Entry Object, if available. Defaults to null.
*
* @return string The field HTML markup.
*/
public function get_field_input( $form, $value = '', $entry = null ) {
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$form_id = absint( $form['id'] );
$id = intval( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$form_sub_label_placement = rgar( $form, 'subLabelPlacement' );
$field_sub_label_placement = $this->subLabelPlacement;
$is_sub_label_above = $field_sub_label_placement == 'above' || ( empty( $field_sub_label_placement ) && $form_sub_label_placement == 'above' );
$sub_label_class_attribute = $field_sub_label_placement == 'hidden_label' ? "class='hidden_sub_label screen-reader-text'" : '';
$disabled_text = $is_form_editor ? "disabled='disabled'" : '';
$hour = $minute = $am_selected = $pm_selected = '';
if ( ! is_array( $value ) && ! empty( $value ) ) {
preg_match( '/^(\d*):(\d*) ?(.*)$/', $value, $matches );
$hour = esc_attr( $matches[1] );
$minute = esc_attr( $matches[2] );
$the_rest = strtolower( rgar( $matches, 3 ) );
$am_selected = strpos( $the_rest, 'am' ) > -1 ? "selected='selected'" : '';
$pm_selected = strpos( $the_rest, 'pm' ) > -1 ? "selected='selected'" : '';
} elseif ( is_array( $value ) ) {
$value = array_values( $value );
$hour = esc_attr( $value[0] );
$minute = esc_attr( $value[1] );
$am_selected = strtolower( rgar( $value, 2 ) ) == 'am' ? "selected='selected'" : '';
$pm_selected = strtolower( rgar( $value, 2 ) ) == 'pm' ? "selected='selected'" : '';
}
$hour_input = GFFormsModel::get_input( $this, $this->id . '.1' );
$minute_input = GFFormsModel::get_input( $this, $this->id . '.2' );
$hour_placeholder_attribute = $this->get_input_placeholder_attribute( $hour_input );
$minute_placeholder_attribute = $this->get_input_placeholder_attribute( $minute_input );
$hour_tabindex = $this->get_tabindex();
$minute_tabindex = $this->get_tabindex();
$ampm_tabindex = $this->get_tabindex();
$is_html5 = RGFormsModel::is_html5_enabled();
$input_type = $is_html5 ? 'number' : 'text';
$max_hour = $this->timeFormat == '24' ? 24 : 12;
$hour_html5_attributes = $is_html5 ? "min='0' max='{$max_hour}' step='1'" : '';
$minute_html5_attributes = $is_html5 ? "min='0' max='59' step='1'" : '';
$ampm_field_style = $is_form_editor && $this->timeFormat == '24' ? "style='display:none;'" : '';
if ( $is_form_editor || $this->timeFormat != '24' ) {
$am_text = esc_html__( 'AM', 'gravityforms' );
$pm_text = esc_html__( 'PM', 'gravityforms' );
$aria_label = esc_attr( 'AM/PM', 'gravityforms' );
$ampm_field = "<div class='gfield_time_ampm ginput_container ginput_container_time' {$ampm_field_style}>
" . ( $is_sub_label_above ? "<div class='gfield_time_ampm_shim' aria-hidden='true'> </div>" : "" ). "
<select name='input_{$id}[]' id='{$field_id}_3' $ampm_tabindex {$disabled_text} aria-label='{$aria_label}'>
<option value='am' {$am_selected}>{$am_text}</option>
<option value='pm' {$pm_selected}>{$pm_text}</option>
</select>
</div>";
} else {
$ampm_field = '';
}
$hour_label = rgar( $hour_input, 'customLabel' ) != '' ? $hour_input['customLabel'] : esc_html__( 'HH', 'gravityforms' );
$minute_label = rgar( $minute_input, 'customLabel' ) != '' ? $minute_input['customLabel'] : esc_html( _x( 'MM', 'Abbreviation: Minutes', 'gravityforms' ) );
if ( $is_sub_label_above ) {
return "<div class='clear-multi'>
<div class='gfield_time_hour ginput_container ginput_container_time' id='{$field_id}'>
<label for='{$field_id}_1' {$sub_label_class_attribute}>{$hour_label}</label>
<input type='{$input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_1' value='{$hour}' {$hour_tabindex} {$hour_html5_attributes} {$disabled_text} {$hour_placeholder_attribute}/> <i>:</i>
</div>
<div class='gfield_time_minute ginput_container ginput_container_time'>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$minute_label}</label>
<input type='{$input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_2' value='{$minute}' {$minute_tabindex} {$minute_html5_attributes} {$disabled_text} {$minute_placeholder_attribute}/>
</div>
{$ampm_field}
</div>";
} else {
return "<div class='clear-multi'>
<div class='gfield_time_hour ginput_container ginput_container_time' id='{$field_id}'>
<input type='{$input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_1' value='{$hour}' {$hour_tabindex} {$hour_html5_attributes} {$disabled_text} {$hour_placeholder_attribute}/> <i>:</i>
<label for='{$field_id}_1' {$sub_label_class_attribute}>{$hour_label}</label>
</div>
<div class='gfield_time_minute ginput_container ginput_container_time'>
<input type='{$input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_2' value='{$minute}' {$minute_tabindex} {$minute_html5_attributes} {$disabled_text} {$minute_placeholder_attribute}/>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$minute_label}</label>
</div>
{$ampm_field}
</div>";
}
}
/**
* Adds additional classes to the field labels.
*
* @since Unknown
* @access public
*
* @used-by GF_Field::get_field_content()
*
* @return string The class string to use for the Time field.
*/
public function get_field_label_class(){
return 'gfield_label gfield_label_before_complex';
}
/**
* Whether this field expects an array during submission.
*
* @since 2.4
*
* @return bool
*/
public function is_value_submission_array() {
return true;
}
/**
* Determines if any of the submission values are empty.
*
* @since Unknown
* @access public
*
* @used-by GFFormDisplay::is_empty()
*
* @param int $form_id The form ID.
*
* @return bool True if empty. False otherwise.
*/
public function is_value_submission_empty( $form_id ) {
$value = rgpost( 'input_' . $this->id );
if ( is_array( $value ) ) {
// Date field and date drop-downs.
foreach ( $value as $input ) {
if ( strlen( trim( $input ) ) <= 0 ) {
return true;
}
}
return false;
} else {
// Date picker.
return strlen( trim( $value ) ) <= 0;
}
}
/**
* Determines whether the given value is considered empty for this field.
*
* @since 2.4
*
* @param string|array $value The value.
*
* @return bool True if empty. False otherwise.
*/
public function is_value_empty( $value ) {
if ( is_array( $value ) ) {
foreach ( $value as $input ) {
if ( strlen( trim( $input ) ) <= 0 ) {
return true;
}
}
return false;
} else {
return strlen( trim( $value ) ) <= 0;
}
}
/**
* Prepares the field value to be saved after an entry is submitted.
*
* @since Unknown
* @access public
*
* @used-by GFFormsModel::prepare_value()
*
* @param string $value The value to prepare.
* @param array $form The Form Object. Not used.
* @param string $input_name The name of the input. Not used.
* @param int $lead_id The entry ID. Not used.
* @param array $lead The Entry Object. Not used.
*
* @return array|string The field value, prepared and stripped of tags.
*/
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
if ( empty( $value ) && ! is_array( $value ) ) {
return '';
}
// If $value is a default value and also an array, it will be an associative array; to be safe, let's convert all array $value to numeric.
if ( is_array( $value ) ) {
$value = array_values( $value );
}
if ( ! is_array( $value ) && ! empty( $value ) ) {
preg_match( '/^(\d*):(\d*) ?(.*)$/', $value, $matches );
$value = array();
$value[0] = $matches[1];
$value[1] = $matches[2];
$value[2] = rgar( $matches, 3 );
}
$hour = wp_strip_all_tags( $value[0] );
$minute = wp_strip_all_tags( $value[1] );
$ampm = wp_strip_all_tags( rgar( $value, 2 ) );
if ( ! empty( $ampm ) ) {
$ampm = " $ampm";
}
if ( ! ( rgblank( $hour ) && rgblank( $minute ) ) ) {
$value = sprintf( '%02d:%02d%s', $hour, $minute, $ampm );
} else {
$value = '';
}
return $value;
}
/**
* Returns a JS script to be rendered in the front end of the form.
*
* @param array $form The Form Object
*
* @return string Returns a JS script to be processed in the front end.
*/
public function get_form_inline_script_on_page_render( $form ) {
//Only return merge tag script if form supports JS merge tags
if ( ! GFFormDisplay::has_js_merge_tag( $form ) ) {
return '';
}
return "gform.addFilter( 'gform_value_merge_tag_{$form['id']}_{$this->id}', function( value, input, modifier ) { if( modifier === 'label' ) { return false; } var ampm = input.length == 3 ? ' ' + jQuery(input[2]).val() : ''; return jQuery(input[0]).val() + ':' + jQuery(input[1]).val() + ' ' + ampm; } );";
}
/**
* Overrides GF_Field to prevent the standard input ID from being used.
*
* @since Unknown
* @access public
*
* @return null
*/
public function get_entry_inputs() {
return null;
}
/**
* Removes the "for" attribute in the field label. Inputs are only allowed one label (a11y) and the inputs already have labels.
*
* @since 2.4
* @access public
*
* @param array $form The Form Object currently being processed.
*
* @return string
*/
public function get_first_input_id( $form ) {
return '';
}
/**
* Sanitizes settings for the Time field.
*
* @since Unknown
* @access public
*
* @used-by GFFormDetail::add_field()
* @used-by GFFormsModel::sanitize_settings()
* @uses GF_Field::sanitize_settings
* @uses GF_Field_Time::$timeFormat
*
* @return void
*/
public function sanitize_settings() {
parent::sanitize_settings();
if ( ! $this->timeFormat || ! in_array( $this->timeFormat, array( 12, 24 ) ) ) {
$this->timeFormat = '12';
}
}
}
// Register the Time field with the field framework.
GF_Fields::register( new GF_Field_Time() );
class-gf-field-quantity.php 0000666 00000001231 15126403614 0011714 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Quantity extends GF_Field {
public $type = 'quantity';
function get_form_editor_field_settings() {
return array(
'product_field_setting',
'quantity_field_type_setting',
'conditional_logic_field_setting',
'prepopulate_field_setting',
'label_setting',
'admin_label_setting',
'label_placement_setting',
'default_value_setting',
'placeholder_setting',
'description_setting',
'css_class_setting',
);
}
public function get_form_editor_field_title() {
return esc_attr__( 'Quantity', 'gravityforms' );
}
}
GF_Fields::register( new GF_Field_Quantity() ); class-gf-field-post-tags.php 0000666 00000004106 15126403614 0011763 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Post_Tags extends GF_Field {
public $type = 'post_tags';
public function get_form_editor_field_title() {
return esc_attr__( 'Tags', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'post_tag_type_setting',
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'rules_setting',
'default_value_setting',
'visibility_setting',
'description_setting',
'css_class_setting',
'placeholder_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$value = esc_attr( $value );
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$class = esc_attr( $class );
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$tabindex = $this->get_tabindex();
$placeholder_attribute = $this->get_field_placeholder_attribute();
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$aria_describedby = $this->get_aria_describedby();
return "<div class='ginput_container ginput_container_post_tags'>
<input name='input_{$id}' id='{$field_id}' type='text' value='{$value}' class='{$class}' {$tabindex} {$placeholder_attribute} {$required_attribute} {$invalid_attribute} {$aria_describedby} {$disabled_text}/>
</div>";
}
public function allow_html() {
return true;
}
}
GF_Fields::register( new GF_Field_Post_Tags() ); class-gf-field-address.php 0000666 00000164566 15126403614 0011510 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Address extends GF_Field {
public $type = 'address';
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'admin_label_setting',
'label_placement_setting',
'sub_label_placement_setting',
'default_input_values_setting',
'input_placeholders_setting',
'address_setting',
'rules_setting',
'copy_values_option',
'description_setting',
'visibility_setting',
'css_class_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
public function get_form_editor_field_title() {
return esc_attr__( 'Address', 'gravityforms' );
}
function validate( $value, $form ) {
if ( $this->isRequired ) {
$copy_values_option_activated = $this->enableCopyValuesOption && rgpost( 'input_' . $this->id . '_copy_values_activated' );
if ( $copy_values_option_activated ) {
// validation will occur in the source field
return;
}
$street = rgar( $value, $this->id . '.1' );
$city = rgar( $value, $this->id . '.3' );
$state = rgar( $value, $this->id . '.4' );
$zip = rgar( $value, $this->id . '.5' );
$country = rgar( $value, $this->id . '.6' );
if ( empty( $street ) && ! $this->get_input_property( $this->id . '.1', 'isHidden' )
|| empty( $city ) && ! $this->get_input_property( $this->id . '.3', 'isHidden' )
|| empty( $zip ) && ! $this->get_input_property( $this->id . '.5', 'isHidden' )
|| ( empty( $state ) && ! ( $this->hideState || $this->get_input_property( $this->id . '.4', 'isHidden' ) ) )
|| ( empty( $country ) && ! ( $this->hideCountry || $this->get_input_property( $this->id . '.6', 'isHidden' ) ) )
) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'This field is required. Please enter a complete address.', 'gravityforms' ) : $this->errorMessage;
}
}
}
public function get_value_submission( $field_values, $get_from_post_global_var = true ) {
$value = parent::get_value_submission( $field_values, $get_from_post_global_var );
$value[ $this->id . '_copy_values_activated' ] = (bool) rgpost( 'input_' . $this->id . '_copy_values_activated' );
return $value;
}
public function get_field_input( $form, $value = '', $entry = null ) {
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$is_admin = $is_entry_detail || $is_form_editor;
$form_id = absint( $form['id'] );
$id = intval( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$form_id = ( $is_entry_detail || $is_form_editor ) && empty( $form_id ) ? rgget( 'id' ) : $form_id;
$disabled_text = $is_form_editor ? "disabled='disabled'" : '';
$class_suffix = $is_entry_detail ? '_admin' : '';
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$form_sub_label_placement = rgar( $form, 'subLabelPlacement' );
$field_sub_label_placement = $this->subLabelPlacement;
$is_sub_label_above = $field_sub_label_placement == 'above' || ( empty( $field_sub_label_placement ) && $form_sub_label_placement == 'above' );
$sub_label_class_attribute = $field_sub_label_placement == 'hidden_label' ? "class='hidden_sub_label screen-reader-text'" : '';
$street_value = '';
$street2_value = '';
$city_value = '';
$state_value = '';
$zip_value = '';
$country_value = '';
if ( is_array( $value ) ) {
$street_value = esc_attr( rgget( $this->id . '.1', $value ) );
$street2_value = esc_attr( rgget( $this->id . '.2', $value ) );
$city_value = esc_attr( rgget( $this->id . '.3', $value ) );
$state_value = esc_attr( rgget( $this->id . '.4', $value ) );
$zip_value = esc_attr( rgget( $this->id . '.5', $value ) );
$country_value = esc_attr( rgget( $this->id . '.6', $value ) );
}
// Inputs.
$address_street_field_input = GFFormsModel::get_input( $this, $this->id . '.1' );
$address_street2_field_input = GFFormsModel::get_input( $this, $this->id . '.2' );
$address_city_field_input = GFFormsModel::get_input( $this, $this->id . '.3' );
$address_state_field_input = GFFormsModel::get_input( $this, $this->id . '.4' );
$address_zip_field_input = GFFormsModel::get_input( $this, $this->id . '.5' );
$address_country_field_input = GFFormsModel::get_input( $this, $this->id . '.6' );
// Placeholders.
$street_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $address_street_field_input );
$street2_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $address_street2_field_input );
$city_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $address_city_field_input );
$zip_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $address_zip_field_input );
$address_types = $this->get_address_types( $form_id );
$addr_type = empty( $this->addressType ) ? $this->get_default_address_type( $form_id ) : $this->addressType;
$address_type = rgar( $address_types, $addr_type );
$state_label = empty( $address_type['state_label'] ) ? esc_html__( 'State', 'gravityforms' ) : $address_type['state_label'];
$zip_label = empty( $address_type['zip_label'] ) ? esc_html__( 'Zip Code', 'gravityforms' ) : $address_type['zip_label'];
$hide_country = ! empty( $address_type['country'] ) || $this->hideCountry || rgar( $address_country_field_input, 'isHidden' );
if ( empty( $country_value ) ) {
$country_value = $this->defaultCountry;
}
if ( empty( $state_value ) ) {
$state_value = $this->defaultState;
}
$country_placeholder = GFCommon::get_input_placeholder_value( $address_country_field_input );
$country_list = $this->get_country_dropdown( $country_value, $country_placeholder );
// Changing css classes based on field format to ensure proper display.
$address_display_format = apply_filters( 'gform_address_display_format', 'default', $this );
$city_location = $address_display_format == 'zip_before_city' ? 'right' : 'left';
$zip_location = $address_display_format != 'zip_before_city' && ( $this->hideState || rgar( $address_state_field_input, 'isHidden' ) ) ? 'right' : 'left'; // support for $this->hideState legacy property
$state_location = $address_display_format == 'zip_before_city' ? 'left' : 'right';
$country_location = $this->hideState || rgar( $address_state_field_input, 'isHidden' ) ? 'left' : 'right'; // support for $this->hideState legacy property
// Labels.
$address_street_sub_label = rgar( $address_street_field_input, 'customLabel' ) != '' ? $address_street_field_input['customLabel'] : esc_html__( 'Street Address', 'gravityforms' );
$address_street_sub_label = gf_apply_filters( array( 'gform_address_street', $form_id, $this->id ), $address_street_sub_label, $form_id );
$address_street2_sub_label = rgar( $address_street2_field_input, 'customLabel' ) != '' ? $address_street2_field_input['customLabel'] : esc_html__( 'Address Line 2', 'gravityforms' );
$address_street2_sub_label = gf_apply_filters( array( 'gform_address_street2', $form_id, $this->id ), $address_street2_sub_label, $form_id );
$address_zip_sub_label = rgar( $address_zip_field_input, 'customLabel' ) != '' ? $address_zip_field_input['customLabel'] : $zip_label;
$address_zip_sub_label = gf_apply_filters( array( 'gform_address_zip', $form_id, $this->id ), $address_zip_sub_label, $form_id );
$address_city_sub_label = rgar( $address_city_field_input, 'customLabel' ) != '' ? $address_city_field_input['customLabel'] : esc_html__( 'City', 'gravityforms' );
$address_city_sub_label = gf_apply_filters( array( 'gform_address_city', $form_id, $this->id ), $address_city_sub_label, $form_id );
$address_state_sub_label = rgar( $address_state_field_input, 'customLabel' ) != '' ? $address_state_field_input['customLabel'] : $state_label;
$address_state_sub_label = gf_apply_filters( array( 'gform_address_state', $form_id, $this->id ), $address_state_sub_label, $form_id );
$address_country_sub_label = rgar( $address_country_field_input, 'customLabel' ) != '' ? $address_country_field_input['customLabel'] : esc_html__( 'Country', 'gravityforms' );
$address_country_sub_label = gf_apply_filters( array( 'gform_address_country', $form_id, $this->id ), $address_country_sub_label, $form_id );
// Address field.
$street_address = '';
$tabindex = $this->get_tabindex();
$style = ( $is_admin && rgar( $address_street_field_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $address_street_field_input, 'isHidden' ) ) {
if ( $is_sub_label_above ) {
$street_address = " <span class='ginput_full{$class_suffix} address_line_1' id='{$field_id}_1_container' {$style}>
<label for='{$field_id}_1' id='{$field_id}_1_label' {$sub_label_class_attribute}>{$address_street_sub_label}</label>
<input type='text' name='input_{$id}.1' id='{$field_id}_1' value='{$street_value}' {$tabindex} {$disabled_text} {$street_placeholder_attribute} {$required_attribute}/>
</span>";
} else {
$street_address = " <span class='ginput_full{$class_suffix} address_line_1' id='{$field_id}_1_container' {$style}>
<input type='text' name='input_{$id}.1' id='{$field_id}_1' value='{$street_value}' {$tabindex} {$disabled_text} {$street_placeholder_attribute} {$required_attribute}/>
<label for='{$field_id}_1' id='{$field_id}_1_label' {$sub_label_class_attribute}>{$address_street_sub_label}</label>
</span>";
}
}
// Address line 2 field.
$street_address2 = '';
$style = ( $is_admin && ( $this->hideAddress2 || rgar( $address_street2_field_input, 'isHidden' ) ) ) ? "style='display:none;'" : ''; // support for $this->hideAddress2 legacy property
if ( $is_admin || ( ! $this->hideAddress2 && ! rgar( $address_street2_field_input, 'isHidden' ) ) ) {
$tabindex = $this->get_tabindex();
if ( $is_sub_label_above ) {
$street_address2 = "<span class='ginput_full{$class_suffix} address_line_2' id='{$field_id}_2_container' {$style}>
<label for='{$field_id}_2' id='{$field_id}_2_label' {$sub_label_class_attribute}>{$address_street2_sub_label}</label>
<input type='text' name='input_{$id}.2' id='{$field_id}_2' value='{$street2_value}' {$tabindex} {$disabled_text} {$street2_placeholder_attribute}/>
</span>";
} else {
$street_address2 = "<span class='ginput_full{$class_suffix} address_line_2' id='{$field_id}_2_container' {$style}>
<input type='text' name='input_{$id}.2' id='{$field_id}_2' value='{$street2_value}' {$tabindex} {$disabled_text} {$street2_placeholder_attribute}/>
<label for='{$field_id}_2' id='{$field_id}_2_label' {$sub_label_class_attribute}>{$address_street2_sub_label}</label>
</span>";
}
}
if ( $address_display_format == 'zip_before_city' ) {
// Zip field.
$zip = '';
$tabindex = $this->get_tabindex();
$style = ( $is_admin && rgar( $address_zip_field_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $address_zip_field_input, 'isHidden' ) ) {
if ( $is_sub_label_above ) {
$zip = "<span class='ginput_{$zip_location}{$class_suffix} address_zip' id='{$field_id}_5_container' {$style}>
<label for='{$field_id}_5' id='{$field_id}_5_label' {$sub_label_class_attribute}>{$address_zip_sub_label}</label>
<input type='text' name='input_{$id}.5' id='{$field_id}_5' value='{$zip_value}' {$tabindex} {$disabled_text} {$zip_placeholder_attribute} {$required_attribute}/>
</span>";
} else {
$zip = "<span class='ginput_{$zip_location}{$class_suffix} address_zip' id='{$field_id}_5_container' {$style}>
<input type='text' name='input_{$id}.5' id='{$field_id}_5' value='{$zip_value}' {$tabindex} {$disabled_text} {$zip_placeholder_attribute} {$required_attribute}/>
<label for='{$field_id}_5' id='{$field_id}_5_label' {$sub_label_class_attribute}>{$address_zip_sub_label}</label>
</span>";
}
}
// City field.
$city = '';
$tabindex = $this->get_tabindex();
$style = ( $is_admin && rgar( $address_city_field_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $address_city_field_input, 'isHidden' ) ) {
if ( $is_sub_label_above ) {
$city = "<span class='ginput_{$city_location}{$class_suffix} address_city' id='{$field_id}_3_container' {$style}>
<label for='{$field_id}_3' id='{$field_id}_3_label' {$sub_label_class_attribute}>{$address_city_sub_label}</label>
<input type='text' name='input_{$id}.3' id='{$field_id}_3' value='{$city_value}' {$tabindex} {$disabled_text} {$city_placeholder_attribute} {$required_attribute}/>
</span>";
} else {
$city = "<span class='ginput_{$city_location}{$class_suffix} address_city' id='{$field_id}_3_container' {$style}>
<input type='text' name='input_{$id}.3' id='{$field_id}_3' value='{$city_value}' {$tabindex} {$disabled_text} {$city_placeholder_attribute} {$required_attribute}/>
<label for='{$field_id}_3' id='{$field_id}_3_label' {$sub_label_class_attribute}>{$address_city_sub_label}</label>
</span>";
}
}
// State field.
$style = ( $is_admin && ( $this->hideState || rgar( $address_state_field_input, 'isHidden' ) ) ) ? "style='display:none;'" : ''; // support for $this->hideState legacy property
if ( $is_admin || ( ! $this->hideState && ! rgar( $address_state_field_input, 'isHidden' ) ) ) {
$state_field = $this->get_state_field( $id, $field_id, $state_value, $disabled_text, $form_id );
if ( $is_sub_label_above ) {
$state = "<span class='ginput_{$state_location}{$class_suffix} address_state' id='{$field_id}_4_container' {$style}>
<label for='{$field_id}_4' id='{$field_id}_4_label' {$sub_label_class_attribute}>{$address_state_sub_label}</label>
$state_field
</span>";
} else {
$state = "<span class='ginput_{$state_location}{$class_suffix} address_state' id='{$field_id}_4_container' {$style}>
$state_field
<label for='{$field_id}_4' id='{$field_id}_4_label' {$sub_label_class_attribute}>{$address_state_sub_label}</label>
</span>";
}
} else {
$state = sprintf( "<input type='hidden' class='gform_hidden' name='input_%d.4' id='%s_4' value='%s'/>", $id, $field_id, $state_value );
}
} else {
// City field.
$city = '';
$tabindex = $this->get_tabindex();
$style = ( $is_admin && rgar( $address_city_field_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $address_city_field_input, 'isHidden' ) ) {
if ( $is_sub_label_above ) {
$city = "<span class='ginput_{$city_location}{$class_suffix} address_city' id='{$field_id}_3_container' {$style}>
<label for='{$field_id}_3' id='{$field_id}_3_label' {$sub_label_class_attribute}>{$address_city_sub_label}</label>
<input type='text' name='input_{$id}.3' id='{$field_id}_3' value='{$city_value}' {$tabindex} {$disabled_text} {$city_placeholder_attribute} {$required_attribute}/>
</span>";
} else {
$city = "<span class='ginput_{$city_location}{$class_suffix} address_city' id='{$field_id}_3_container' {$style}>
<input type='text' name='input_{$id}.3' id='{$field_id}_3' value='{$city_value}' {$tabindex} {$disabled_text} {$city_placeholder_attribute} {$required_attribute}/>
<label for='{$field_id}_3' id='{$field_id}_3_label' {$sub_label_class_attribute}>{$address_city_sub_label}</label>
</span>";
}
}
// State field.
$style = ( $is_admin && ( $this->hideState || rgar( $address_state_field_input, 'isHidden' ) ) ) ? "style='display:none;'" : ''; // support for $this->hideState legacy property
if ( $is_admin || ( ! $this->hideState && ! rgar( $address_state_field_input, 'isHidden' ) ) ) {
$state_field = $this->get_state_field( $id, $field_id, $state_value, $disabled_text, $form_id );
if ( $is_sub_label_above ) {
$state = "<span class='ginput_{$state_location}{$class_suffix} address_state' id='{$field_id}_4_container' {$style}>
<label for='{$field_id}_4' id='{$field_id}_4_label' {$sub_label_class_attribute}>$address_state_sub_label</label>
$state_field
</span>";
} else {
$state = "<span class='ginput_{$state_location}{$class_suffix} address_state' id='{$field_id}_4_container' {$style}>
$state_field
<label for='{$field_id}_4' id='{$field_id}_4_label' {$sub_label_class_attribute}>$address_state_sub_label</label>
</span>";
}
} else {
$state = sprintf( "<input type='hidden' class='gform_hidden' name='input_%d.4' id='%s_4' value='%s'/>", $id, $field_id, $state_value );
}
// Zip field.
$zip = '';
$tabindex = GFCommon::get_tabindex();
$style = ( $is_admin && rgar( $address_zip_field_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $address_zip_field_input, 'isHidden' ) ) {
if ( $is_sub_label_above ) {
$zip = "<span class='ginput_{$zip_location}{$class_suffix} address_zip' id='{$field_id}_5_container' {$style}>
<label for='{$field_id}_5' id='{$field_id}_5_label' {$sub_label_class_attribute}>{$address_zip_sub_label}</label>
<input type='text' name='input_{$id}.5' id='{$field_id}_5' value='{$zip_value}' {$tabindex} {$disabled_text} {$zip_placeholder_attribute} {$required_attribute}/>
</span>";
} else {
$zip = "<span class='ginput_{$zip_location}{$class_suffix} address_zip' id='{$field_id}_5_container' {$style}>
<input type='text' name='input_{$id}.5' id='{$field_id}_5' value='{$zip_value}' {$tabindex} {$disabled_text} {$zip_placeholder_attribute} {$required_attribute}/>
<label for='{$field_id}_5' id='{$field_id}_5_label' {$sub_label_class_attribute}>{$address_zip_sub_label}</label>
</span>";
}
}
}
if ( $is_admin || ! $hide_country ) {
$style = $hide_country ? "style='display:none;'" : '';
$tabindex = $this->get_tabindex();
if ( $is_sub_label_above ) {
$country = "<span class='ginput_{$country_location}{$class_suffix} address_country' id='{$field_id}_6_container' {$style}>
<label for='{$field_id}_6' id='{$field_id}_6_label' {$sub_label_class_attribute}>{$address_country_sub_label}</label>
<select name='input_{$id}.6' id='{$field_id}_6' {$tabindex} {$disabled_text} {$required_attribute}>{$country_list}</select>
</span>";
} else {
$country = "<span class='ginput_{$country_location}{$class_suffix} address_country' id='{$field_id}_6_container' {$style}>
<select name='input_{$id}.6' id='{$field_id}_6' {$tabindex} {$disabled_text} {$required_attribute}>{$country_list}</select>
<label for='{$field_id}_6' id='{$field_id}_6_label' {$sub_label_class_attribute}>{$address_country_sub_label}</label>
</span>";
}
} else {
$country = sprintf( "<input type='hidden' class='gform_hidden' name='input_%d.6' id='%s_6' value='%s'/>", $id, $field_id, $country_value );
}
$inputs = $address_display_format == 'zip_before_city' ? $street_address . $street_address2 . $zip . $city . $state . $country : $street_address . $street_address2 . $city . $state . $zip . $country;
$copy_values_option = '';
$input_style = '';
if ( ( $this->enableCopyValuesOption || $is_form_editor ) && ! $is_entry_detail ) {
$copy_values_label = esc_html( $this->copyValuesOptionLabel );
$copy_values_style = $is_form_editor && ! $this->enableCopyValuesOption ? "style='display:none;'" : '';
$copy_values_is_checked = isset( $value[$this->id . '_copy_values_activated'] ) ? $value[$this->id . '_copy_values_activated'] == true : $this->copyValuesOptionDefault == true;
$copy_values_checked = checked( true, $copy_values_is_checked, false );
$copy_values_option = "<div id='{$field_id}_copy_values_option_container' class='copy_values_option_container' {$copy_values_style}>
<input type='checkbox' id='{$field_id}_copy_values_activated' class='copy_values_activated' value='1' name='input_{$id}_copy_values_activated' {$disabled_text} {$copy_values_checked}/>
<label for='{$field_id}_copy_values_activated' id='{$field_id}_copy_values_option_label' class='copy_values_option_label inline'>{$copy_values_label}</label>
</div>";
if ( $copy_values_is_checked ) {
$input_style = "style='display:none;'";
}
}
$css_class = $this->get_css_class();
return " {$copy_values_option}
<div class='ginput_complex{$class_suffix} ginput_container {$css_class}' id='$field_id' {$input_style}>
{$inputs}
<div class='gf_clear gf_clear_complex'></div>
</div>";
}
public function get_field_label_class(){
return 'gfield_label gfield_label_before_complex';
}
public function get_css_class() {
$address_street_field_input = GFFormsModel::get_input( $this, $this->id . '.1' );
$address_street2_field_input = GFFormsModel::get_input( $this, $this->id . '.2' );
$address_city_field_input = GFFormsModel::get_input( $this, $this->id . '.3' );
$address_state_field_input = GFFormsModel::get_input( $this, $this->id . '.4' );
$address_zip_field_input = GFFormsModel::get_input( $this, $this->id . '.5' );
$address_country_field_input = GFFormsModel::get_input( $this, $this->id . '.6' );
$css_class = '';
if ( ! rgar( $address_street_field_input, 'isHidden' ) ) {
$css_class .= 'has_street ';
}
if ( ! rgar( $address_street2_field_input, 'isHidden' ) ) {
$css_class .= 'has_street2 ';
}
if ( ! rgar( $address_city_field_input, 'isHidden' ) ) {
$css_class .= 'has_city ';
}
if ( ! rgar( $address_state_field_input, 'isHidden' ) ) {
$css_class .= 'has_state ';
}
if ( ! rgar( $address_zip_field_input, 'isHidden' ) ) {
$css_class .= 'has_zip ';
}
if ( ! rgar( $address_country_field_input, 'isHidden' ) ) {
$css_class .= 'has_country ';
}
$css_class .= 'ginput_container_address';
return trim( $css_class );
}
public function get_address_types( $form_id ) {
$addressTypes = array(
'international' => array( 'label' => esc_html__( 'International', 'gravityforms' ),
'zip_label' => gf_apply_filters( array( 'gform_address_zip', $form_id ), esc_html__( 'ZIP / Postal Code', 'gravityforms' ), $form_id ),
'state_label' => gf_apply_filters( array( 'gform_address_state', $form_id ), esc_html__( 'State / Province / Region', 'gravityforms' ), $form_id )
),
'us' => array(
'label' => esc_html__( 'United States', 'gravityforms' ),
'zip_label' => gf_apply_filters( array( 'gform_address_zip', $form_id ), esc_html__( 'ZIP Code', 'gravityforms' ), $form_id ),
'state_label' => gf_apply_filters( array( 'gform_address_state', $form_id ), esc_html__( 'State', 'gravityforms' ), $form_id ),
'country' => 'United States',
'states' => array_merge( array( '' ), $this->get_us_states() )
),
'canadian' => array(
'label' => esc_html__( 'Canadian', 'gravityforms' ),
'zip_label' => gf_apply_filters( array( 'gform_address_zip', $form_id ), esc_html__( 'Postal Code', 'gravityforms' ), $form_id ),
'state_label' => gf_apply_filters( array( 'gform_address_state', $form_id ), esc_html__( 'Province', 'gravityforms' ), $form_id ),
'country' => 'Canada',
'states' => array_merge( array( '' ), $this->get_canadian_provinces() )
)
);
/**
* Filters the address types available.
*
* @since Unknown
*
* @param array $addressTypes Contains the details for existing address types.
* @param int $form_id The form ID.
*/
return gf_apply_filters( array( 'gform_address_types', $form_id ), $addressTypes, $form_id );
}
/**
* Retrieve the default address type for this field.
*
* @param int $form_id The current form ID.
*
* @return string
*/
public function get_default_address_type( $form_id ) {
$default_address_type = 'international';
/**
* Allow the default address type to be overridden.
*
* @param string $default_address_type The default address type of international.
*/
$default_address_type = apply_filters( 'gform_default_address_type', $default_address_type, $form_id );
return apply_filters( 'gform_default_address_type_' . $form_id, $default_address_type, $form_id );
}
public function get_state_field( $id, $field_id, $state_value, $disabled_text, $form_id ) {
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$is_admin = $is_entry_detail || $is_form_editor;
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$state_dropdown_class = $state_text_class = $state_style = $text_style = $state_field_id = '';
if ( empty( $state_value ) ) {
$state_value = $this->defaultState;
// For backwards compatibility (Canadian address type used to store the default state into the defaultProvince property).
if ( $this->addressType == 'canadian' && ! empty( $this->defaultProvince ) ) {
$state_value = $this->defaultProvince;
}
}
$address_type = empty( $this->addressType ) ? $this->get_default_address_type( $form_id ) : $this->addressType;
$address_types = $this->get_address_types( $form_id );
$has_state_drop_down = isset( $address_types[ $address_type ]['states'] ) && is_array( $address_types[ $address_type ]['states'] );
if ( $is_admin && rgget('view') != 'entry' ) {
$state_dropdown_class = "class='state_dropdown'";
$state_text_class = "class='state_text'";
$state_style = ! $has_state_drop_down ? "style='display:none;'" : '';
$text_style = $has_state_drop_down ? "style='display:none;'" : '';
$state_field_id = '';
} else {
// ID only displayed on front end.
$state_field_id = "id='" . $field_id . "_4'";
}
$tabindex = $this->get_tabindex();
$state_input = GFFormsModel::get_input( $this, $this->id . '.4' );
$sate_placeholder = GFCommon::get_input_placeholder_value( $state_input );
$states = empty( $address_types[ $address_type ]['states'] ) ? array() : $address_types[ $address_type ]['states'];
$state_dropdown = sprintf( "<select name='input_%d.4' %s {$tabindex} %s {$state_dropdown_class} {$state_style} {$required_attribute}>%s</select>", $id, $state_field_id, $disabled_text, $this->get_state_dropdown( $states, $state_value, $sate_placeholder ) );
$tabindex = $this->get_tabindex();
$state_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $state_input );
$state_text = sprintf( "<input type='text' name='input_%d.4' %s value='%s' {$tabindex} %s {$state_text_class} {$text_style} {$state_placeholder_attribute} {$required_attribute}/>", $id, $state_field_id, $state_value, $disabled_text );
if ( $is_admin && rgget('view') != 'entry' ) {
return $state_dropdown . $state_text;
} elseif ( $has_state_drop_down ) {
return $state_dropdown;
} else {
return $state_text;
}
}
/**
* Returns a list of countries.
*
* @since Unknown
* @since 2.4 Updated to use ISO 3166-1 list of countries.
* @since 2.4.20 Updated to use GF_Field_Address::get_default_countries() and to sort the countries.
*
* @return array
*/
public function get_countries() {
$countries = array_values( $this->get_default_countries() );
sort( $countries );
/**
* A list of countries displayed in the Address field country drop down.
*
* @since Unknown
*
* @param array $countries ISO 3166-1 list of countries.
*/
return apply_filters( 'gform_countries', $countries );
}
/**
* Returns the default array of countries using the ISO 3166-1 alpha-2 code as the key to the country name.
*
* @since 2.4.20
*
* @return array
*/
public function get_default_countries() {
return array(
'AF' => __( 'Afghanistan', 'gravityforms' ),
'AX' => __( 'Åland Islands', 'gravityforms' ),
'AL' => __( 'Albania', 'gravityforms' ),
'DZ' => __( 'Algeria', 'gravityforms' ),
'AS' => __( 'American Samoa', 'gravityforms' ),
'AD' => __( 'Andorra', 'gravityforms' ),
'AO' => __( 'Angola', 'gravityforms' ),
'AI' => __( 'Anguilla', 'gravityforms' ),
'AQ' => __( 'Antarctica', 'gravityforms' ),
'AG' => __( 'Antigua and Barbuda', 'gravityforms' ),
'AR' => __( 'Argentina', 'gravityforms' ),
'AM' => __( 'Armenia', 'gravityforms' ),
'AW' => __( 'Aruba', 'gravityforms' ),
'AU' => __( 'Australia', 'gravityforms' ),
'AT' => __( 'Austria', 'gravityforms' ),
'AZ' => __( 'Azerbaijan', 'gravityforms' ),
'BS' => __( 'Bahamas', 'gravityforms' ),
'BH' => __( 'Bahrain', 'gravityforms' ),
'BD' => __( 'Bangladesh', 'gravityforms' ),
'BB' => __( 'Barbados', 'gravityforms' ),
'BY' => __( 'Belarus', 'gravityforms' ),
'BE' => __( 'Belgium', 'gravityforms' ),
'BZ' => __( 'Belize', 'gravityforms' ),
'BJ' => __( 'Benin', 'gravityforms' ),
'BM' => __( 'Bermuda', 'gravityforms' ),
'BT' => __( 'Bhutan', 'gravityforms' ),
'BO' => __( 'Bolivia', 'gravityforms' ),
'BQ' => __( 'Bonaire, Sint Eustatius and Saba', 'gravityforms' ),
'BA' => __( 'Bosnia and Herzegovina', 'gravityforms' ),
'BW' => __( 'Botswana', 'gravityforms' ),
'BV' => __( 'Bouvet Island', 'gravityforms' ),
'BR' => __( 'Brazil', 'gravityforms' ),
'IO' => __( 'British Indian Ocean Territory', 'gravityforms' ),
'BN' => __( 'Brunei Darussalam', 'gravityforms' ),
'BG' => __( 'Bulgaria', 'gravityforms' ),
'BF' => __( 'Burkina Faso', 'gravityforms' ),
'BI' => __( 'Burundi', 'gravityforms' ),
'KH' => __( 'Cambodia', 'gravityforms' ),
'CM' => __( 'Cameroon', 'gravityforms' ),
'CA' => __( 'Canada', 'gravityforms' ),
'CV' => __( 'Cape Verde', 'gravityforms' ),
'KY' => __( 'Cayman Islands', 'gravityforms' ),
'CF' => __( 'Central African Republic', 'gravityforms' ),
'TD' => __( 'Chad', 'gravityforms' ),
'CL' => __( 'Chile', 'gravityforms' ),
'CN' => __( 'China', 'gravityforms' ),
'CX' => __( 'Christmas Island', 'gravityforms' ),
'CC' => __( 'Cocos Islands', 'gravityforms' ),
'CO' => __( 'Colombia', 'gravityforms' ),
'KM' => __( 'Comoros', 'gravityforms' ),
'CD' => __( 'Congo, Democratic Republic of the', 'gravityforms' ),
'CG' => __( 'Congo, Republic of the', 'gravityforms' ),
'CK' => __( 'Cook Islands', 'gravityforms' ),
'CR' => __( 'Costa Rica', 'gravityforms' ),
'CI' => __( "Côte d'Ivoire", 'gravityforms' ),
'HR' => __( 'Croatia', 'gravityforms' ),
'CU' => __( 'Cuba', 'gravityforms' ),
'CW' => __( 'Curaçao', 'gravityforms' ),
'CY' => __( 'Cyprus', 'gravityforms' ),
'CZ' => __( 'Czech Republic', 'gravityforms' ),
'DK' => __( 'Denmark', 'gravityforms' ),
'DJ' => __( 'Djibouti', 'gravityforms' ),
'DM' => __( 'Dominica', 'gravityforms' ),
'DO' => __( 'Dominican Republic', 'gravityforms' ),
'EC' => __( 'Ecuador', 'gravityforms' ),
'EG' => __( 'Egypt', 'gravityforms' ),
'SV' => __( 'El Salvador', 'gravityforms' ),
'GQ' => __( 'Equatorial Guinea', 'gravityforms' ),
'ER' => __( 'Eritrea', 'gravityforms' ),
'EE' => __( 'Estonia', 'gravityforms' ),
'SZ' => __( 'Eswatini (Swaziland)', 'gravityforms' ),
'ET' => __( 'Ethiopia', 'gravityforms' ),
'FK' => __( 'Falkland Islands', 'gravityforms' ),
'FO' => __( 'Faroe Islands', 'gravityforms' ),
'FJ' => __( 'Fiji', 'gravityforms' ),
'FI' => __( 'Finland', 'gravityforms' ),
'FR' => __( 'France', 'gravityforms' ),
'GF' => __( 'French Guiana', 'gravityforms' ),
'PF' => __( 'French Polynesia', 'gravityforms' ),
'TF' => __( 'French Southern Territories', 'gravityforms' ),
'GA' => __( 'Gabon', 'gravityforms' ),
'GM' => __( 'Gambia', 'gravityforms' ),
'GE' => _x( 'Georgia', 'Country', 'gravityforms' ),
'DE' => __( 'Germany', 'gravityforms' ),
'GH' => __( 'Ghana', 'gravityforms' ),
'GI' => __( 'Gibraltar', 'gravityforms' ),
'GR' => __( 'Greece', 'gravityforms' ),
'GL' => __( 'Greenland', 'gravityforms' ),
'GD' => __( 'Grenada', 'gravityforms' ),
'GP' => __( 'Guadeloupe', 'gravityforms' ),
'GU' => __( 'Guam', 'gravityforms' ),
'GT' => __( 'Guatemala', 'gravityforms' ),
'GG' => __( 'Guernsey', 'gravityforms' ),
'GN' => __( 'Guinea', 'gravityforms' ),
'GW' => __( 'Guinea-Bissau', 'gravityforms' ),
'GY' => __( 'Guyana', 'gravityforms' ),
'HT' => __( 'Haiti', 'gravityforms' ),
'HM' => __( 'Heard and McDonald Islands', 'gravityforms' ),
'VA' => __( 'Holy See', 'gravityforms' ),
'HN' => __( 'Honduras', 'gravityforms' ),
'HK' => __( 'Hong Kong', 'gravityforms' ),
'HU' => __( 'Hungary', 'gravityforms' ),
'IS' => __( 'Iceland', 'gravityforms' ),
'IN' => __( 'India', 'gravityforms' ),
'ID' => __( 'Indonesia', 'gravityforms' ),
'IR' => __( 'Iran', 'gravityforms' ),
'IQ' => __( 'Iraq', 'gravityforms' ),
'IE' => __( 'Ireland', 'gravityforms' ),
'IM' => __( 'Isle of Man', 'gravityforms' ),
'IL' => __( 'Israel', 'gravityforms' ),
'IT' => __( 'Italy', 'gravityforms' ),
'JM' => __( 'Jamaica', 'gravityforms' ),
'JP' => __( 'Japan', 'gravityforms' ),
'JE' => __( 'Jersey', 'gravityforms' ),
'JO' => __( 'Jordan', 'gravityforms' ),
'KZ' => __( 'Kazakhstan', 'gravityforms' ),
'KE' => __( 'Kenya', 'gravityforms' ),
'KI' => __( 'Kiribati', 'gravityforms' ),
'KW' => __( 'Kuwait', 'gravityforms' ),
'KG' => __( 'Kyrgyzstan', 'gravityforms' ),
'LA' => __( "Lao People's Democratic Republic", 'gravityforms' ),
'LV' => __( 'Latvia', 'gravityforms' ),
'LB' => __( 'Lebanon', 'gravityforms' ),
'LS' => __( 'Lesotho', 'gravityforms' ),
'LR' => __( 'Liberia', 'gravityforms' ),
'LY' => __( 'Libya', 'gravityforms' ),
'LI' => __( 'Liechtenstein', 'gravityforms' ),
'LT' => __( 'Lithuania', 'gravityforms' ),
'LU' => __( 'Luxembourg', 'gravityforms' ),
'MO' => __( 'Macau', 'gravityforms' ),
'MK' => __( 'Macedonia', 'gravityforms' ),
'MG' => __( 'Madagascar', 'gravityforms' ),
'MW' => __( 'Malawi', 'gravityforms' ),
'MY' => __( 'Malaysia', 'gravityforms' ),
'MV' => __( 'Maldives', 'gravityforms' ),
'ML' => __( 'Mali', 'gravityforms' ),
'MT' => __( 'Malta', 'gravityforms' ),
'MH' => __( 'Marshall Islands', 'gravityforms' ),
'MQ' => __( 'Martinique', 'gravityforms' ),
'MR' => __( 'Mauritania', 'gravityforms' ),
'MU' => __( 'Mauritius', 'gravityforms' ),
'YT' => __( 'Mayotte', 'gravityforms' ),
'MX' => __( 'Mexico', 'gravityforms' ),
'FM' => __( 'Micronesia', 'gravityforms' ),
'MD' => __( 'Moldova', 'gravityforms' ),
'MC' => __( 'Monaco', 'gravityforms' ),
'MN' => __( 'Mongolia', 'gravityforms' ),
'ME' => __( 'Montenegro', 'gravityforms' ),
'MS' => __( 'Montserrat', 'gravityforms' ),
'MA' => __( 'Morocco', 'gravityforms' ),
'MZ' => __( 'Mozambique', 'gravityforms' ),
'MM' => __( 'Myanmar', 'gravityforms' ),
'NA' => __( 'Namibia', 'gravityforms' ),
'NR' => __( 'Nauru', 'gravityforms' ),
'NP' => __( 'Nepal', 'gravityforms' ),
'NL' => __( 'Netherlands', 'gravityforms' ),
'NC' => __( 'New Caledonia', 'gravityforms' ),
'NZ' => __( 'New Zealand', 'gravityforms' ),
'NI' => __( 'Nicaragua', 'gravityforms' ),
'NE' => __( 'Niger', 'gravityforms' ),
'NG' => __( 'Nigeria', 'gravityforms' ),
'NU' => __( 'Niue', 'gravityforms' ),
'NF' => __( 'Norfolk Island', 'gravityforms' ),
'KP' => __( 'North Korea', 'gravityforms' ),
'MP' => __( 'Northern Mariana Islands', 'gravityforms' ),
'NO' => __( 'Norway', 'gravityforms' ),
'OM' => __( 'Oman', 'gravityforms' ),
'PK' => __( 'Pakistan', 'gravityforms' ),
'PW' => __( 'Palau', 'gravityforms' ),
'PS' => __( 'Palestine, State of', 'gravityforms' ),
'PA' => __( 'Panama', 'gravityforms' ),
'PG' => __( 'Papua New Guinea', 'gravityforms' ),
'PY' => __( 'Paraguay', 'gravityforms' ),
'PE' => __( 'Peru', 'gravityforms' ),
'PH' => __( 'Philippines', 'gravityforms' ),
'PN' => __( 'Pitcairn', 'gravityforms' ),
'PL' => __( 'Poland', 'gravityforms' ),
'PT' => __( 'Portugal', 'gravityforms' ),
'PR' => __( 'Puerto Rico', 'gravityforms' ),
'QA' => __( 'Qatar', 'gravityforms' ),
'RE' => __( 'Réunion', 'gravityforms' ),
'RO' => __( 'Romania', 'gravityforms' ),
'RU' => __( 'Russia', 'gravityforms' ),
'RW' => __( 'Rwanda', 'gravityforms' ),
'BL' => __( 'Saint Barthélemy', 'gravityforms' ),
'SH' => __( 'Saint Helena', 'gravityforms' ),
'KN' => __( 'Saint Kitts and Nevis', 'gravityforms' ),
'LC' => __( 'Saint Lucia', 'gravityforms' ),
'MF' => __( 'Saint Martin', 'gravityforms' ),
'PM' => __( 'Saint Pierre and Miquelon', 'gravityforms' ),
'VC' => __( 'Saint Vincent and the Grenadines', 'gravityforms' ),
'WS' => __( 'Samoa', 'gravityforms' ),
'SM' => __( 'San Marino', 'gravityforms' ),
'ST' => __( 'Sao Tome and Principe', 'gravityforms' ),
'SA' => __( 'Saudi Arabia', 'gravityforms' ),
'SN' => __( 'Senegal', 'gravityforms' ),
'RS' => __( 'Serbia', 'gravityforms' ),
'SC' => __( 'Seychelles', 'gravityforms' ),
'SL' => __( 'Sierra Leone', 'gravityforms' ),
'SG' => __( 'Singapore', 'gravityforms' ),
'SX' => __( 'Sint Maarten', 'gravityforms' ),
'SK' => __( 'Slovakia', 'gravityforms' ),
'SI' => __( 'Slovenia', 'gravityforms' ),
'SB' => __( 'Solomon Islands', 'gravityforms' ),
'SO' => __( 'Somalia', 'gravityforms' ),
'ZA' => __( 'South Africa', 'gravityforms' ),
'GS' => _x( 'South Georgia', 'Country', 'gravityforms' ),
'KR' => __( 'South Korea', 'gravityforms' ),
'SS' => __( 'South Sudan', 'gravityforms' ),
'ES' => __( 'Spain', 'gravityforms' ),
'LK' => __( 'Sri Lanka', 'gravityforms' ),
'SD' => __( 'Sudan', 'gravityforms' ),
'SR' => __( 'Suriname', 'gravityforms' ),
'SJ' => __( 'Svalbard and Jan Mayen Islands', 'gravityforms' ),
'SE' => __( 'Sweden', 'gravityforms' ),
'CH' => __( 'Switzerland', 'gravityforms' ),
'SY' => __( 'Syria', 'gravityforms' ),
'TW' => __( 'Taiwan', 'gravityforms' ),
'TJ' => __( 'Tajikistan', 'gravityforms' ),
'TZ' => __( 'Tanzania', 'gravityforms' ),
'TH' => __( 'Thailand', 'gravityforms' ),
'TL' => __( 'Timor-Leste', 'gravityforms' ),
'TG' => __( 'Togo', 'gravityforms' ),
'TK' => __( 'Tokelau', 'gravityforms' ),
'TO' => __( 'Tonga', 'gravityforms' ),
'TT' => __( 'Trinidad and Tobago', 'gravityforms' ),
'TN' => __( 'Tunisia', 'gravityforms' ),
'TR' => __( 'Turkey', 'gravityforms' ),
'TM' => __( 'Turkmenistan', 'gravityforms' ),
'TC' => __( 'Turks and Caicos Islands', 'gravityforms' ),
'TV' => __( 'Tuvalu', 'gravityforms' ),
'UG' => __( 'Uganda', 'gravityforms' ),
'UA' => __( 'Ukraine', 'gravityforms' ),
'AE' => __( 'United Arab Emirates', 'gravityforms' ),
'GB' => __( 'United Kingdom', 'gravityforms' ),
'US' => __( 'United States', 'gravityforms' ),
'UY' => __( 'Uruguay', 'gravityforms' ),
'UM' => __( 'US Minor Outlying Islands', 'gravityforms' ),
'UZ' => __( 'Uzbekistan', 'gravityforms' ),
'VU' => __( 'Vanuatu', 'gravityforms' ),
'VE' => __( 'Venezuela', 'gravityforms' ),
'VN' => __( 'Vietnam', 'gravityforms' ),
'VG' => __( 'Virgin Islands, British', 'gravityforms' ),
'VI' => __( 'Virgin Islands, U.S.', 'gravityforms' ),
'WF' => __( 'Wallis and Futuna', 'gravityforms' ),
'EH' => __( 'Western Sahara', 'gravityforms' ),
'YE' => __( 'Yemen', 'gravityforms' ),
'ZM' => __( 'Zambia', 'gravityforms' ),
'ZW' => __( 'Zimbabwe', 'gravityforms' ),
);
}
/**
* Returns the ISO 3166-1 alpha-2 code for the supplied country name.
*
* @since Unknown
*
* @param string $country_name The country name.
*
* @return string|null
*/
public function get_country_code( $country_name ) {
$codes = $this->get_country_codes();
return rgar( $codes, GFCommon::safe_strtoupper( $country_name ) );
}
/**
* Returns the default countries array updated to use the uppercase country name as the key to the ISO 3166-1 alpha-2 code.
*
* @since Unknown
* @since 2.4 Updated to use ISO 3166-1 list of countries.
* @since 2.4.20 Updated to use GF_Field_Address::get_default_countries().
*
* @return array
*/
public function get_country_codes() {
$countries = array_map( array( 'GFCommon', 'safe_strtoupper' ), $this->get_default_countries() );
return array_flip( $countries );
}
public function get_us_states() {
return apply_filters(
'gform_us_states', array(
__( 'Alabama', 'gravityforms' ),
__( 'Alaska', 'gravityforms' ),
__( 'Arizona', 'gravityforms' ),
__( 'Arkansas', 'gravityforms' ),
__( 'California', 'gravityforms' ),
__( 'Colorado', 'gravityforms' ),
__( 'Connecticut', 'gravityforms' ),
__( 'Delaware', 'gravityforms' ),
__( 'District of Columbia', 'gravityforms' ),
__( 'Florida', 'gravityforms' ),
_x( 'Georgia', 'US State', 'gravityforms' ),
__( 'Hawaii', 'gravityforms' ),
__( 'Idaho', 'gravityforms' ),
__( 'Illinois', 'gravityforms' ),
__( 'Indiana', 'gravityforms' ),
__( 'Iowa', 'gravityforms' ),
__( 'Kansas', 'gravityforms' ),
__( 'Kentucky', 'gravityforms' ),
__( 'Louisiana', 'gravityforms' ),
__( 'Maine', 'gravityforms' ),
__( 'Maryland', 'gravityforms' ),
__( 'Massachusetts', 'gravityforms' ),
__( 'Michigan', 'gravityforms' ),
__( 'Minnesota', 'gravityforms' ),
__( 'Mississippi', 'gravityforms' ),
__( 'Missouri', 'gravityforms' ),
__( 'Montana', 'gravityforms' ),
__( 'Nebraska', 'gravityforms' ),
__( 'Nevada', 'gravityforms' ),
__( 'New Hampshire', 'gravityforms' ),
__( 'New Jersey', 'gravityforms' ),
__( 'New Mexico', 'gravityforms' ),
__( 'New York', 'gravityforms' ),
__( 'North Carolina', 'gravityforms' ),
__( 'North Dakota', 'gravityforms' ),
__( 'Ohio', 'gravityforms' ),
__( 'Oklahoma', 'gravityforms' ),
__( 'Oregon', 'gravityforms' ),
__( 'Pennsylvania', 'gravityforms' ),
__( 'Rhode Island', 'gravityforms' ),
__( 'South Carolina', 'gravityforms' ),
__( 'South Dakota', 'gravityforms' ),
__( 'Tennessee', 'gravityforms' ),
__( 'Texas', 'gravityforms' ),
__( 'Utah', 'gravityforms' ),
__( 'Vermont', 'gravityforms' ),
__( 'Virginia', 'gravityforms' ),
__( 'Washington', 'gravityforms' ),
__( 'West Virginia', 'gravityforms' ),
__( 'Wisconsin', 'gravityforms' ),
__( 'Wyoming', 'gravityforms' ),
__( 'Armed Forces Americas', 'gravityforms' ),
__( 'Armed Forces Europe', 'gravityforms' ),
__( 'Armed Forces Pacific', 'gravityforms' ),
)
);
}
public function get_us_state_code( $state_name ) {
$states = array(
GFCommon::safe_strtoupper( __( 'Alabama', 'gravityforms' ) ) => 'AL',
GFCommon::safe_strtoupper( __( 'Alaska', 'gravityforms' ) ) => 'AK',
GFCommon::safe_strtoupper( __( 'Arizona', 'gravityforms' ) ) => 'AZ',
GFCommon::safe_strtoupper( __( 'Arkansas', 'gravityforms' ) ) => 'AR',
GFCommon::safe_strtoupper( __( 'California', 'gravityforms' ) ) => 'CA',
GFCommon::safe_strtoupper( __( 'Colorado', 'gravityforms' ) ) => 'CO',
GFCommon::safe_strtoupper( __( 'Connecticut', 'gravityforms' ) ) => 'CT',
GFCommon::safe_strtoupper( __( 'Delaware', 'gravityforms' ) ) => 'DE',
GFCommon::safe_strtoupper( __( 'District of Columbia', 'gravityforms' ) ) => 'DC',
GFCommon::safe_strtoupper( __( 'Florida', 'gravityforms' ) ) => 'FL',
GFCommon::safe_strtoupper( _x( 'Georgia', 'US State', 'gravityforms' ) ) => 'GA',
GFCommon::safe_strtoupper( __( 'Hawaii', 'gravityforms' ) ) => 'HI',
GFCommon::safe_strtoupper( __( 'Idaho', 'gravityforms' ) ) => 'ID',
GFCommon::safe_strtoupper( __( 'Illinois', 'gravityforms' ) ) => 'IL',
GFCommon::safe_strtoupper( __( 'Indiana', 'gravityforms' ) ) => 'IN',
GFCommon::safe_strtoupper( __( 'Iowa', 'gravityforms' ) ) => 'IA',
GFCommon::safe_strtoupper( __( 'Kansas', 'gravityforms' ) ) => 'KS',
GFCommon::safe_strtoupper( __( 'Kentucky', 'gravityforms' ) ) => 'KY',
GFCommon::safe_strtoupper( __( 'Louisiana', 'gravityforms' ) ) => 'LA',
GFCommon::safe_strtoupper( __( 'Maine', 'gravityforms' ) ) => 'ME',
GFCommon::safe_strtoupper( __( 'Maryland', 'gravityforms' ) ) => 'MD',
GFCommon::safe_strtoupper( __( 'Massachusetts', 'gravityforms' ) ) => 'MA',
GFCommon::safe_strtoupper( __( 'Michigan', 'gravityforms' ) ) => 'MI',
GFCommon::safe_strtoupper( __( 'Minnesota', 'gravityforms' ) ) => 'MN',
GFCommon::safe_strtoupper( __( 'Mississippi', 'gravityforms' ) ) => 'MS',
GFCommon::safe_strtoupper( __( 'Missouri', 'gravityforms' ) ) => 'MO',
GFCommon::safe_strtoupper( __( 'Montana', 'gravityforms' ) ) => 'MT',
GFCommon::safe_strtoupper( __( 'Nebraska', 'gravityforms' ) ) => 'NE',
GFCommon::safe_strtoupper( __( 'Nevada', 'gravityforms' ) ) => 'NV',
GFCommon::safe_strtoupper( __( 'New Hampshire', 'gravityforms' ) ) => 'NH',
GFCommon::safe_strtoupper( __( 'New Jersey', 'gravityforms' ) ) => 'NJ',
GFCommon::safe_strtoupper( __( 'New Mexico', 'gravityforms' ) ) => 'NM',
GFCommon::safe_strtoupper( __( 'New York', 'gravityforms' ) ) => 'NY',
GFCommon::safe_strtoupper( __( 'North Carolina', 'gravityforms' ) ) => 'NC',
GFCommon::safe_strtoupper( __( 'North Dakota', 'gravityforms' ) ) => 'ND',
GFCommon::safe_strtoupper( __( 'Ohio', 'gravityforms' ) ) => 'OH',
GFCommon::safe_strtoupper( __( 'Oklahoma', 'gravityforms' ) ) => 'OK',
GFCommon::safe_strtoupper( __( 'Oregon', 'gravityforms' ) ) => 'OR',
GFCommon::safe_strtoupper( __( 'Pennsylvania', 'gravityforms' ) ) => 'PA',
GFCommon::safe_strtoupper( __( 'Rhode Island', 'gravityforms' ) ) => 'RI',
GFCommon::safe_strtoupper( __( 'South Carolina', 'gravityforms' ) ) => 'SC',
GFCommon::safe_strtoupper( __( 'South Dakota', 'gravityforms' ) ) => 'SD',
GFCommon::safe_strtoupper( __( 'Tennessee', 'gravityforms' ) ) => 'TN',
GFCommon::safe_strtoupper( __( 'Texas', 'gravityforms' ) ) => 'TX',
GFCommon::safe_strtoupper( __( 'Utah', 'gravityforms' ) ) => 'UT',
GFCommon::safe_strtoupper( __( 'Vermont', 'gravityforms' ) ) => 'VT',
GFCommon::safe_strtoupper( __( 'Virginia', 'gravityforms' ) ) => 'VA',
GFCommon::safe_strtoupper( __( 'Washington', 'gravityforms' ) ) => 'WA',
GFCommon::safe_strtoupper( __( 'West Virginia', 'gravityforms' ) ) => 'WV',
GFCommon::safe_strtoupper( __( 'Wisconsin', 'gravityforms' ) ) => 'WI',
GFCommon::safe_strtoupper( __( 'Wyoming', 'gravityforms' ) ) => 'WY',
GFCommon::safe_strtoupper( __( 'Armed Forces Americas', 'gravityforms' ) ) => 'AA',
GFCommon::safe_strtoupper( __( 'Armed Forces Europe', 'gravityforms' ) ) => 'AE',
GFCommon::safe_strtoupper( __( 'Armed Forces Pacific', 'gravityforms' ) ) => 'AP',
);
$state_name = GFCommon::safe_strtoupper( $state_name );
$code = isset( $states[ $state_name ] ) ? $states[ $state_name ] : $state_name;
return $code;
}
public function get_canadian_provinces() {
return array(
__( 'Alberta', 'gravityforms' ),
__( 'British Columbia', 'gravityforms' ),
__( 'Manitoba', 'gravityforms' ),
__( 'New Brunswick', 'gravityforms' ),
__( 'Newfoundland and Labrador', 'gravityforms' ),
__( 'Northwest Territories', 'gravityforms' ),
__( 'Nova Scotia', 'gravityforms' ),
__( 'Nunavut', 'gravityforms' ),
__( 'Ontario', 'gravityforms' ),
__( 'Prince Edward Island', 'gravityforms' ),
__( 'Quebec', 'gravityforms' ),
__( 'Saskatchewan', 'gravityforms' ),
__( 'Yukon', 'gravityforms' )
);
}
public function get_state_dropdown( $states, $selected_state = '', $placeholder = '' ) {
$str = '';
foreach ( $states as $code => $state ) {
if ( is_array( $state ) ) {
$str .= sprintf( '<optgroup label="%1$s">%2$s</optgroup>', esc_attr( $code ), $this->get_state_dropdown( $state, $selected_state, $placeholder ) );
} else {
if ( is_numeric( $code ) ) {
$code = $state;
}
if ( empty( $state ) ) {
$state = $placeholder;
}
$str .= $this->get_select_option( $code, $state, $selected_state );
}
}
return $str;
}
/**
* Returns the option tag for the current choice.
*
* @param string $value The choice value.
* @param string $label The choice label.
* @param string $selected_value The value for the selected choice.
*
* @return string
*/
public function get_select_option( $value, $label, $selected_value ) {
$selected = $value == $selected_value ? "selected='selected'" : '';
return sprintf( "<option value='%s' %s>%s</option>", esc_attr( $value ), $selected, esc_html( $label ) );
}
public function get_us_state_dropdown( $selected_state = '' ) {
$states = array_merge( array( '' ), $this->get_us_states() );
$str = '';
foreach ( $states as $code => $state ) {
if ( is_numeric( $code ) ) {
$code = $state;
}
$selected = $code == $selected_state ? "selected='selected'" : '';
$str .= "<option value='" . esc_attr( $code ) . "' $selected>" . esc_html( $state ) . '</option>';
}
return $str;
}
public function get_canadian_provinces_dropdown( $selected_province = '' ) {
$states = array_merge( array( '' ), $this->get_canadian_provinces() );
$str = '';
foreach ( $states as $state ) {
$selected = $state == $selected_province ? "selected='selected'" : '';
$str .= "<option value='" . esc_attr( $state ) . "' $selected>" . esc_html( $state ) . '</option>';
}
return $str;
}
public function get_country_dropdown( $selected_country = '', $placeholder = '' ) {
$str = '';
$selected_country = strtolower( $selected_country );
$countries = array_merge( array( '' ), $this->get_countries() );
foreach ( $countries as $code => $country ) {
if ( is_numeric( $code ) ) {
$code = $country;
}
if ( empty( $country ) ) {
$country = $placeholder;
}
$selected = strtolower( esc_attr( $code ) ) == $selected_country ? "selected='selected'" : '';
$str .= "<option value='" . esc_attr( $code ) . "' $selected>" . esc_html( $country ) . '</option>';
}
return $str;
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( is_array( $value ) ) {
$street_value = trim( rgget( $this->id . '.1', $value ) );
$street2_value = trim( rgget( $this->id . '.2', $value ) );
$city_value = trim( rgget( $this->id . '.3', $value ) );
$state_value = trim( rgget( $this->id . '.4', $value ) );
$zip_value = trim( rgget( $this->id . '.5', $value ) );
$country_value = trim( rgget( $this->id . '.6', $value ) );
if ( $format === 'html' ) {
$street_value = esc_html( $street_value );
$street2_value = esc_html( $street2_value );
$city_value = esc_html( $city_value );
$state_value = esc_html( $state_value );
$zip_value = esc_html( $zip_value );
$country_value = esc_html( $country_value );
$line_break = '<br />';
} else {
$line_break = "\n";
}
/**
* Filters the format that the address is displayed in.
*
* @since Unknown
*
* @param string 'default' The format to use. Defaults to 'default'.
* @param GF_Field_Address $this An instance of the GF_Field_Address object.
*/
$address_display_format = apply_filters( 'gform_address_display_format', 'default', $this );
if ( $address_display_format == 'zip_before_city' ) {
/*
Sample:
3333 Some Street
suite 16
2344 City, State
Country
*/
$addr_ary = array();
$addr_ary[] = $street_value;
if ( ! empty( $street2_value ) ) {
$addr_ary[] = $street2_value;
}
$zip_line = trim( $zip_value . ' ' . $city_value );
$zip_line .= ! empty( $zip_line ) && ! empty( $state_value ) ? ", {$state_value}" : $state_value;
$zip_line = trim( $zip_line );
if ( ! empty( $zip_line ) ) {
$addr_ary[] = $zip_line;
}
if ( ! empty( $country_value ) ) {
$addr_ary[] = $country_value;
}
$address = implode( '<br />', $addr_ary );
} else {
$address = $street_value;
$address .= ! empty( $address ) && ! empty( $street2_value ) ? $line_break . $street2_value : $street2_value;
$address .= ! empty( $address ) && ( ! empty( $city_value ) || ! empty( $state_value ) ) ? $line_break . $city_value : $city_value;
$address .= ! empty( $address ) && ! empty( $city_value ) && ! empty( $state_value ) ? ", $state_value" : $state_value;
$address .= ! empty( $address ) && ! empty( $zip_value ) ? " $zip_value" : $zip_value;
$address .= ! empty( $address ) && ! empty( $country_value ) ? $line_break . $country_value : $country_value;
}
// Adding map link.
/**
* Disables the Google Maps link from displaying in the address field.
*
* @since 1.9
*
* @param bool false Determines if the map link should be disabled. Set to true to disable. Defaults to false.
*/
$map_link_disabled = apply_filters( 'gform_disable_address_map_link', false );
if ( ! empty( $address ) && $format == 'html' && ! $map_link_disabled ) {
$address_qs = str_replace( $line_break, ' ', $address ); //replacing <br/> and \n with spaces
$address_qs = urlencode( $address_qs );
$address .= "<br/><a href='http://maps.google.com/maps?q={$address_qs}' target='_blank' class='map-it-link'>Map It</a>";
}
return $address;
} else {
return '';
}
}
public function get_input_property( $input_id, $property_name ) {
$input = GFFormsModel::get_input( $this, $input_id );
return rgar( $input, $property_name );
}
public function sanitize_settings() {
parent::sanitize_settings();
if ( $this->addressType ) {
$this->addressType = wp_strip_all_tags( $this->addressType );
}
if ( $this->defaultCountry ) {
$this->defaultCountry = wp_strip_all_tags( $this->defaultCountry );
}
if ( $this->defaultProvince ) {
$this->defaultProvince = wp_strip_all_tags( $this->defaultProvince );
}
if ( $this->copyValuesOptionLabel ) {
$this->copyValuesOptionLabel = wp_strip_all_tags( $this->copyValuesOptionLabel );
}
}
public function get_value_export( $entry, $input_id = '', $use_text = false, $is_csv = false ) {
if ( empty( $input_id ) ) {
$input_id = $this->id;
}
if ( absint( $input_id ) == $input_id ) {
$street_value = str_replace( ' ', ' ', trim( rgar( $entry, $input_id . '.1' ) ) );
$street2_value = str_replace( ' ', ' ', trim( rgar( $entry, $input_id . '.2' ) ) );
$city_value = str_replace( ' ', ' ', trim( rgar( $entry, $input_id . '.3' ) ) );
$state_value = str_replace( ' ', ' ', trim( rgar( $entry, $input_id . '.4' ) ) );
$zip_value = trim( rgar( $entry, $input_id . '.5' ) );
$country_value = $this->get_country_code( trim( rgar( $entry, $input_id . '.6' ) ) );
$address = $street_value;
$address .= ! empty( $address ) && ! empty( $street2_value ) ? " $street2_value" : $street2_value;
$address .= ! empty( $address ) && ( ! empty( $city_value ) || ! empty( $state_value ) ) ? ", $city_value," : $city_value;
$address .= ! empty( $address ) && ! empty( $city_value ) && ! empty( $state_value ) ? " $state_value" : $state_value;
$address .= ! empty( $address ) && ! empty( $zip_value ) ? " $zip_value," : $zip_value;
$address .= ! empty( $address ) && ! empty( $country_value ) ? " $country_value" : $country_value;
return $address;
} else {
return rgar( $entry, $input_id );
}
}
/**
* Removes the "for" attribute in the field label. Inputs are only allowed one label (a11y) and the inputs already have labels.
*
* @since 2.4
* @access public
*
* @param array $form The Form Object currently being processed.
*
* @return string
*/
public function get_first_input_id( $form ) {
return '';
}
// # FIELD FILTER UI HELPERS ---------------------------------------------------------------------------------------
/**
* Returns the sub-filters for the current field.
*
* @since 2.4
*
* @return array
*/
public function get_filter_sub_filters() {
$sub_filters = array();
$inputs = $this->inputs;
foreach ( $inputs as $input ) {
if ( rgar( $input, 'isHidden' ) ) {
continue;
}
$sub_filters[] = array(
'key' => rgar( $input, 'id' ),
'text' => rgar( $input, 'customLabel', rgar( $input, 'label' ) ),
'preventMultiple' => false,
'operators' => $this->get_filter_operators(),
);
}
return $sub_filters;
}
/**
* Returns the filter operators for the current field.
*
* @since 2.4
*
* @return array
*/
public function get_filter_operators() {
$operators = parent::get_filter_operators();
$operators[] = 'contains';
return $operators;
}
}
GF_Fields::register( new GF_Field_Address() );
class-gf-field-number.php 0000666 00000030172 15126403614 0011334 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Number extends GF_Field {
public $type = 'number';
public function get_form_editor_field_title() {
return esc_attr__( 'Number', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'number_format_setting',
'range_setting',
'rules_setting',
'visibility_setting',
'duplicate_setting',
'default_value_setting',
'placeholder_setting',
'description_setting',
'css_class_setting',
'calculation_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
public function get_value_submission( $field_values, $get_from_post_global_var = true ) {
$value = $this->get_input_value_submission( 'input_' . $this->id, $this->inputName, $field_values, $get_from_post_global_var );
if ( is_array( $value ) ) {
$value = array_map( 'trim', $value );
foreach ( $value as &$v ) {
$v = trim( $v );
$v = $this->clean_value( $v );
}
} else {
$value = trim( $value );
$value = $this->clean_value( $value );
}
return $value;
}
/**
* Ensures the POST value is in the correct number format.
*
* @since 2.4
*
* @param $value
*
* @return bool|float|string
*/
public function clean_value( $value ) {
if ( $this->numberFormat == 'currency' ) {
$currency = new RGCurrency( GFCommon::get_currency() );
$value = $currency->to_number( $value );
} elseif ( $this->numberFormat == 'decimal_comma' ) {
$value = GFCommon::clean_number( $value, 'decimal_comma' );
} elseif ( $this->numberFormat == 'decimal_dot' ) {
$value = GFCommon::clean_number( $value, 'decimal_dot' );
}
return $value;
}
public function validate( $value, $form ) {
// The POST value has already been converted from currency or decimal_comma to decimal_dot and then cleaned in get_field_value().
$value = GFCommon::maybe_add_leading_zero( $value );
// Raw value will be tested against the is_numeric() function to make sure it is in the right format.
// If the POST value is an array then the field is inside a repeater so use $value.
$raw_value = isset( $_POST[ 'input_' . $this->id ] ) && ! is_array( $_POST[ 'input_' . $this->id ] ) ? GFCommon::maybe_add_leading_zero( rgpost( 'input_' . $this->id ) ) : $value;
$requires_valid_number = ! rgblank( $raw_value ) && ! $this->has_calculation();
$is_valid_number = $this->validate_range( $value ) && GFCommon::is_numeric( $raw_value, $this->numberFormat );
if ( $requires_valid_number && ! $is_valid_number ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? $this->get_range_message() : $this->errorMessage;
} elseif ( $this->type == 'quantity' ) {
if ( intval( $value ) != $value ) {
$this->failed_validation = true;
$this->validation_message = empty( $field['errorMessage'] ) ? esc_html__( 'Please enter a valid quantity. Quantity cannot contain decimals.', 'gravityforms' ) : $field['errorMessage'];
} elseif ( ! empty( $value ) && ( ! is_numeric( $value ) || intval( $value ) != floatval( $value ) || intval( $value ) < 0 ) ) {
$this->failed_validation = true;
$this->validation_message = empty( $field['errorMessage'] ) ? esc_html__( 'Please enter a valid quantity', 'gravityforms' ) : $field['errorMessage'];
}
}
}
/**
* Validates the range of the number according to the field settings.
*
* @param string $value A decimal_dot formatted string
*
* @return true|false True on valid or false on invalid
*/
private function validate_range( $value ) {
if ( ! GFCommon::is_numeric( $value, 'decimal_dot' ) ) {
return false;
}
$numeric_min = $this->numberFormat == 'decimal_comma' ? GFCommon::clean_number( $this->rangeMin, 'decimal_comma' ) : $this->rangeMin;
$numeric_max = $this->numberFormat == 'decimal_comma' ? GFCommon::clean_number( $this->rangeMax, 'decimal_comma' ) : $this->rangeMax;
if ( ( is_numeric( $numeric_min ) && $value < $numeric_min ) ||
( is_numeric( $numeric_max ) && $value > $numeric_max )
) {
return false;
} else {
return true;
}
}
public function get_range_message() {
$min = $this->rangeMin;
$max = $this->rangeMax;
$numeric_min = $min;
$numeric_max = $max;
if( $this->numberFormat == 'decimal_comma' ){
$numeric_min = empty( $min ) ? '' : GFCommon::clean_number( $min, 'decimal_comma', '');
$numeric_max = empty( $max ) ? '' : GFCommon::clean_number( $max, 'decimal_comma', '');
}
$message = '';
if ( is_numeric( $numeric_min ) && is_numeric( $numeric_max ) ) {
$message = sprintf( esc_html__( 'Please enter a number from %s to %s.', 'gravityforms' ), "<strong>$min</strong>", "<strong>$max</strong>" );
} elseif ( is_numeric( $numeric_min ) ) {
$message = sprintf( esc_html__( 'Please enter a number greater than or equal to %s.', 'gravityforms' ), "<strong>$min</strong>" );
} elseif ( is_numeric( $numeric_max ) ) {
$message = sprintf( esc_html__( 'Please enter a number less than or equal to %s.', 'gravityforms' ), "<strong>$max</strong>" );
} elseif ( $this->failed_validation ) {
$message = esc_html__( 'Please enter a valid number', 'gravityforms' );
}
return $message;
}
public function get_field_input( $form, $value = '', $entry = null ) {
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$form_id = $form['id'];
$id = intval( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$size = $this->size;
$disabled_text = $is_form_editor ? "disabled='disabled'" : '';
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$class = esc_attr( $class );
$instruction = '';
$read_only = '';
if ( ! $is_entry_detail && ! $is_form_editor ) {
if ( $this->has_calculation() ) {
// calculation-enabled fields should be read only
$read_only = 'readonly="readonly"';
} else {
$message = $this->get_range_message();
$validation_class = $this->failed_validation ? 'validation_message' : '';
if ( ! $this->failed_validation && ! empty( $message ) && empty( $this->errorMessage ) ) {
$instruction = "<div class='instruction $validation_class'>" . $message . '</div>';
}
}
} elseif ( rgget('view') == 'entry' ) {
$value = GFCommon::format_number( $value, $this->numberFormat, rgar( $entry, 'currency' ) );
}
$is_html5 = RGFormsModel::is_html5_enabled();
$html_input_type = $is_html5 && ! $this->has_calculation() && ( $this->numberFormat != 'currency' && $this->numberFormat != 'decimal_comma' ) ? 'number' : 'text'; // chrome does not allow number fields to have commas, calculations and currency values display numbers with commas
$step_attr = $is_html5 ? "step='any'" : '';
$min = $this->rangeMin;
$max = $this->rangeMax;
$min_attr = $is_html5 && is_numeric( $min ) ? "min='{$min}'" : '';
$max_attr = $is_html5 && is_numeric( $max ) ? "max='{$max}'" : '';
$include_thousands_sep = apply_filters( 'gform_include_thousands_sep_pre_format_number', $html_input_type == 'text', $this );
$value = GFCommon::format_number( $value, $this->numberFormat, rgar( $entry, 'currency' ), $include_thousands_sep );
$placeholder_attribute = $this->get_field_placeholder_attribute();
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$aria_describedby = $this->get_aria_describedby();
$tabindex = $this->get_tabindex();
$input = sprintf( "<div class='ginput_container ginput_container_number'><input name='input_%d' id='%s' type='{$html_input_type}' {$step_attr} {$min_attr} {$max_attr} value='%s' class='%s' {$tabindex} {$read_only} %s %s %s %s %s/>%s</div>", $id, $field_id, esc_attr( $value ), esc_attr( $class ), $disabled_text, $placeholder_attribute, $required_attribute, $invalid_attribute, $aria_describedby, $instruction );
return $input;
}
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
$include_thousands_sep = apply_filters( 'gform_include_thousands_sep_pre_format_number', true, $this );
return GFCommon::format_number( $value, $this->numberFormat, rgar( $entry, 'currency' ), $include_thousands_sep );
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
$include_thousands_sep = apply_filters( 'gform_include_thousands_sep_pre_format_number', $use_text, $this );
return GFCommon::format_number( $value, $this->numberFormat, $currency, $include_thousands_sep );
}
/**
* Gets merge tag values.
*
* @since Unknown
* @access public
*
* @uses GFCommon::format_number()
*
* @param array|string $value The value of the input.
* @param string $input_id The input ID to use.
* @param array $entry The Entry Object.
* @param array $form The Form Object
* @param string $modifier The modifier passed.
* @param array|string $raw_value The raw value of the input.
* @param bool $url_encode If the result should be URL encoded.
* @param bool $esc_html If the HTML should be escaped.
* @param string $format The format that the value should be.
* @param bool $nl2br If the nl2br function should be used.
*
* @return string The processed merge tag.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
$include_thousands_sep = ! in_array( 'value', $this->get_modifiers() );
/**
* Filters if the thousands separator should be used when displaying the a number field result.
*
* @since 1.9.5
*
* @param bool $include_thousands_sep If the modifier passed in the merge tag is not 'value', false. Otherwise, true.
* @param GF_Field_Number $this An instance of this class.
*/
$include_thousands_sep = apply_filters( 'gform_include_thousands_sep_pre_format_number', $include_thousands_sep, $this );
$formatted_value = GFCommon::format_number( $value, $this->numberFormat, rgar( $entry, 'currency' ), $include_thousands_sep );
return $url_encode ? urlencode( $formatted_value ) : $formatted_value;
}
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
if ( $this->has_calculation() ) {
if ( empty( $lead ) ) {
$lead = GFFormsModel::get_lead( $lead_id );
}
$value = GFCommon::calculate( $this, $form, $lead );
if ( $this->numberFormat !== 'currency' ) {
$value = GFCommon::round_number( $value, $this->calculationRounding );
}
// Return the value as a string when it is zero and a calc so that the "==" comparison done when checking if the field has changed isn't treated as false.
if ( $value == 0 ) {
$value = '0';
}
} else {
$value = $this->clean_number( GFCommon::maybe_add_leading_zero( $value ) );
}
return $this->sanitize_entry_value( $value, $form['id'] );
}
public function sanitize_settings() {
parent::sanitize_settings();
$this->enableCalculation = (bool) $this->enableCalculation;
if ( ! in_array( $this->numberFormat, array( 'currency', 'decimal_comma', 'decimal_dot' ) ) ) {
$this->numberFormat = GFCommon::is_currency_decimal_dot() ? 'decimal_dot' : 'decimal_comma';
}
$this->rangeMin = $this->clean_number( $this->rangeMin );
$this->rangeMax = $this->clean_number( $this->rangeMax );
if ( $this->numberFormat == 'decimal_comma' ) {
$this->rangeMin = GFCommon::format_number( $this->rangeMin, 'decimal_comma' );
$this->rangeMax = GFCommon::format_number( $this->rangeMax, 'decimal_comma' );
}
}
public function clean_number( $value ) {
if ( $this->numberFormat == 'currency' ) {
return GFCommon::to_number( $value );
} else {
return GFCommon::clean_number( $value, $this->numberFormat );
}
}
}
GF_Fields::register( new GF_Field_Number() );
class-gf-field-checkbox.php 0000666 00000057517 15126403614 0011646 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Checkbox extends GF_Field {
/**
* @var string $type The field type.
*/
public $type = 'checkbox';
// # FORM EDITOR & FIELD MARKUP -------------------------------------------------------------------------------------
/**
* Returns the field title.
*
* @since Unknown
* @access public
*
* @return string
*/
public function get_form_editor_field_title() {
return esc_attr__( 'Checkboxes', 'gravityforms' );
}
/**
* The class names of the settings which should be available on the field in the form editor.
*
* @since Unknown
* @access public
*
* @return array
*/
public function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'choices_setting',
'rules_setting',
'visibility_setting',
'description_setting',
'css_class_setting',
'select_all_choices_setting',
);
}
/**
* Indicate if this field type can be used when configuring conditional logic rules.
*
* @since Unknown
* @access public
*
* @return bool
*/
public function is_conditional_logic_supported() {
return true;
}
/**
* Returns the field inner markup.
*
* @since Unknown
* @access public
*
* @param array $form The Form Object currently being processed.
* @param string|array $value The field value. From default/dynamic population, $_POST, or a resumed incomplete submission.
* @param null|array $entry Null or the Entry Object currently being edited.
*
* @uses GF_Field::is_entry_detail()
* @uses GF_Field::is_form_editor()
* @uses GF_Field_Checkbox::get_checkbox_choices()
*
* @return string
*/
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
return sprintf(
"<div class='ginput_container ginput_container_checkbox'><ul class='gfield_checkbox' id='%s'>%s</ul></div>",
esc_attr( $field_id ),
$this->get_checkbox_choices( $value, $disabled_text, $form_id )
);
}
// # SUBMISSION -----------------------------------------------------------------------------------------------------
/**
* Retrieve the field value on submission.
*
* @since Unknown
* @access public
*
* @param array $field_values The dynamic population parameter names with their corresponding values to be populated.
* @param bool|true $get_from_post_global_var Whether to get the value from the $_POST array as opposed to $field_values.
*
* @uses GFFormsModel::choice_value_match()
* @uses GFFormsModel::get_parameter_value()
*
* @return array|string
*/
public function get_value_submission( $field_values, $get_from_post_global_var = true ) {
// Get parameter values for field.
$parameter_values = GFFormsModel::get_parameter_value( $this->inputName, $field_values, $this );
// If parameter values exist but are not an array, convert to array.
if ( ! empty( $parameter_values ) && ! is_array( $parameter_values ) ) {
$parameter_values = explode( ',', $parameter_values );
}
// If no inputs are defined, return an empty string.
if ( ! is_array( $this->inputs ) ) {
return '';
}
// Set initial choice index.
$choice_index = 0;
// Initialize submission value array.
$value = array();
// Loop through field inputs.
foreach ( $this->inputs as $input ) {
if ( ! empty( $_POST[ 'is_submit_' . $this->formId ] ) && $get_from_post_global_var ) {
$input_value = rgpost( 'input_' . str_replace( '.', '_', strval( $input['id'] ) ) );
$value[ strval( $input['id'] ) ] = $input_value;
} else {
if ( is_array( $parameter_values ) ) {
foreach ( $parameter_values as $item ) {
$item = trim( $item );
if ( GFFormsModel::choice_value_match( $this, $this->choices[ $choice_index ], $item ) ) {
$value[ $input['id'] . '' ] = $item;
break;
}
}
}
}
// Increase choice index.
$choice_index ++;
}
return $value;
}
// # ENTRY RELATED --------------------------------------------------------------------------------------------------
/**
* Format the entry value for display on the entries list page.
*
* Return a value that's safe to display on the page.
*
* @since Unknown
* @access public
*
* @param string|array $value The field value.
* @param array $entry The Entry Object currently being processed.
* @param string $field_id The field or input ID currently being processed.
* @param array $columns The properties for the columns being displayed on the entry list page.
* @param array $form The Form Object currently being processed.
*
* @uses GFCommon::implode_non_blank()
* @uses GFCommon::prepare_post_category_value()
* @uses GFCommon::selection_display()
* @uses GF_Field_Checkbox::is_checkbox_checked()
*
* @return string
*/
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
// If this is the main checkbox field (not an input), display a comma separated list of all inputs.
if ( absint( $field_id ) == $field_id ) {
$lead_field_keys = array_keys( $entry );
$items = array();
foreach ( $lead_field_keys as $input_id ) {
if ( is_numeric( $input_id ) && absint( $input_id ) == $field_id ) {
$items[] = GFCommon::selection_display( rgar( $entry, $input_id ), null, $entry['currency'], false );
}
}
$value = GFCommon::implode_non_blank( ', ', $items );
// Special case for post category checkbox fields.
if ( $this->type == 'post_category' ) {
$value = GFCommon::prepare_post_category_value( $value, $this, 'entry_list' );
}
} else {
$value = '';
if ( ! rgblank( $this->is_checkbox_checked( $field_id, $columns[ $field_id ]['label'], $entry ) ) ) {
$value = "<i class='fa fa-check gf_valid'></i>";
}
}
return $value;
}
/**
* Format the entry value for display on the entry detail page and for the {all_fields} merge tag.
*
* Return a value that's safe to display for the context of the given $format.
*
* @since Unknown
* @access public
*
* @param string|array $value The field value.
* @param string $currency The entry currency code.
* @param bool|false $use_text When processing choice based fields should the choice text be returned instead of the value.
* @param string $format The format requested for the location the merge is being used. Possible values: html, text or url.
* @param string $media The location where the value will be displayed. Possible values: screen or email.
*
* @uses GFCommon::selection_display()
*
* @return string
*/
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( is_array( $value ) ) {
$items = '';
foreach ( $value as $key => $item ) {
if ( ! rgblank( $item ) ) {
switch ( $format ) {
case 'text' :
$items .= GFCommon::selection_display( $item, $this, $currency, $use_text ) . ', ';
break;
default:
$items .= '<li>' . wp_kses_post( GFCommon::selection_display( $item, $this, $currency, $use_text ) ) . '</li>';
break;
}
}
}
if ( empty( $items ) ) {
return '';
} elseif ( $format == 'text' ) {
return substr( $items, 0, strlen( $items ) - 2 ); // Removing last comma.
} else {
return "<ul class='bulleted'>$items</ul>";
}
} else {
return $value;
}
}
/**
* Gets merge tag values.
*
* @since Unknown
* @access public
*
* @uses GFCommon::to_money()
* @uses GFCommon::format_post_category()
* @uses GFFormsModel::is_field_hidden()
* @uses GFFormsModel::get_choice_text()
* @uses GFCommon::format_variable_value()
* @uses GFCommon::implode_non_blank()
*
* @param array|string $value The value of the input.
* @param string $input_id The input ID to use.
* @param array $entry The Entry Object.
* @param array $form The Form Object
* @param string $modifier The modifier passed.
* @param array|string $raw_value The raw value of the input.
* @param bool $url_encode If the result should be URL encoded.
* @param bool $esc_html If the HTML should be escaped.
* @param string $format The format that the value should be.
* @param bool $nl2br If the nl2br function should be used.
*
* @uses GFCommon::format_post_category()
* @uses GFCommon::format_variable_value()
* @uses GFCommon::implode_non_blank()
* @uses GFCommon::to_money()
* @uses GFFormsModel::is_field_hidden()
*
* @return string The processed merge tag.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
// Check for passed modifiers.
$use_value = $modifier == 'value';
$use_price = in_array( $modifier, array( 'price', 'currency' ) );
$format_currency = $modifier == 'currency';
if ( is_array( $raw_value ) && (string) intval( $input_id ) != $input_id ) {
$items = array( $input_id => $value ); // Float input IDs. (i.e. 4.1 ). Used when targeting specific checkbox items.
} elseif ( is_array( $raw_value ) ) {
$items = $raw_value;
} else {
$items = array( $input_id => $raw_value );
}
$ary = array();
// Get the items available within the merge tags.
foreach ( $items as $input_id => $item ) {
// If the 'value' modifier was passed.
if ( $use_value ) {
list( $val, $price ) = rgexplode( '|', $item, 2 );
// If the 'price' or 'currency' modifiers were passed.
} elseif ( $use_price ) {
list( $name, $val ) = rgexplode( '|', $item, 2 );
if ( $format_currency ) {
$val = GFCommon::to_money( $val, rgar( $entry, 'currency' ) );
}
// If this is a post category checkbox.
} else if ( $this->type == 'post_category' ) {
$use_id = strtolower( $modifier ) == 'id';
$item_value = GFCommon::format_post_category( $item, $use_id );
$val = GFFormsModel::is_field_hidden( $form, $this, array(), $entry ) ? '' : $item_value;
// If no modifiers were passed.
} else {
$val = GFFormsModel::is_field_hidden( $form, $this, array(), $entry ) ? '' : RGFormsModel::get_choice_text( $this, $raw_value, $input_id );
}
$ary[] = GFCommon::format_variable_value( $val, $url_encode, $esc_html, $format );
}
return GFCommon::implode_non_blank( ', ', $ary );
}
/**
* Sanitize and format the value before it is saved to the Entry Object.
*
* @since Unknown
* @access public
*
* @param string $value The value to be saved.
* @param array $form The Form Object currently being processed.
* @param string $input_name The input name used when accessing the $_POST.
* @param int $lead_id The ID of the Entry currently being processed.
* @param array $lead The Entry Object currently being processed.
*
* @uses GF_Field_Checkbox::sanitize_entry_value()
*
* @return array|string The safe value.
*/
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
if ( rgblank( $value ) ) {
return '';
} elseif ( is_array( $value ) ) {
foreach ( $value as &$v ) {
if ( is_array( $v ) ) {
$v = '';
}
$v = $this->sanitize_entry_value( $v, $form['id'] );
}
return implode( ',', $value );
} else {
return $this->sanitize_entry_value( $value, $form['id'] );
}
}
/**
* Format the entry value before it is used in entry exports and by framework add-ons using GFAddOn::get_field_value().
*
* @since Unknown
* @access public
*
* @param array $entry The entry currently being processed.
* @param string $input_id The field or input ID.
* @param bool|false $use_text When processing choice based fields should the choice text be returned instead of the value.
* @param bool|false $is_csv Is the value going to be used in the .csv entries export?
*
* @uses GFCommon::get_label()
* @uses GFCommon::selection_display()
* @uses GF_Field_Checkbox::is_checkbox_checked()
*
* @return string
*/
public function get_value_export( $entry, $input_id = '', $use_text = false, $is_csv = false ) {
if ( empty( $input_id ) || absint( $input_id ) == $input_id ) {
$selected = array();
foreach ( $this->inputs as $input ) {
$index = (string) $input['id'];
if ( ! rgempty( $index, $entry ) ) {
$selected[] = GFCommon::selection_display( rgar( $entry, $index ), $this, rgar( $entry, 'currency' ), $use_text );
}
}
return implode( ', ', $selected );
} else if ( $is_csv ) {
$value = $this->is_checkbox_checked( $input_id, GFCommon::get_label( $this, $input_id ), $entry );
return empty( $value ) ? '' : $value;
} else {
return GFCommon::selection_display( rgar( $entry, $input_id ), $this, rgar( $entry, 'currency' ), $use_text );
}
}
// # INPUT ATTRIBUTE HELPERS ----------------------------------------------------------------------------------------
/**
* Get checkbox choice inputs for field.
*
* @since Unknown
* @access public
*
* @param string|array $value The field value. From default/dynamic population, $_POST, or a resumed incomplete submission.
* @param string $disabled_text The HTML disabled attribute.
* @param int $form_id The current form ID.
*
* @uses GFCommon::to_number()
* @uses GF_Field::get_conditional_logic_event()
* @uses GF_Field::get_tabindex()
* @uses GF_Field::is_entry_detail()
* @uses GF_Field::is_form_editor()
* @uses GFFormsModel::choice_value_match()
*
* @return string
*/
public function get_checkbox_choices( $value, $disabled_text, $form_id = 0 ) {
$choices = '';
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
if ( is_array( $this->choices ) ) {
$choice_number = 1;
$count = 1;
// Add Select All choice.
if ( $this->enableSelectAll ) {
/**
* Modify the "Select All" checkbox label.
*
* @since 2.3
*
* @param string $select_label The "Select All" label.
* @param object $field The field currently being processed.
*/
$select_label = gf_apply_filters( array( 'gform_checkbox_select_all_label', $this->formId, $this->id ), esc_html__( 'Select All', 'gravityforms' ), $this );
$select_label = esc_html( $select_label );
/**
* Modify the "Deselect All" checkbox label.
*
* @since 2.3
*
* @param string $deselect_label The "Deselect All" label.
* @param object $field The field currently being processed.
*/
$deselect_label = gf_apply_filters( array( 'gform_checkbox_deselect_all_label', $this->formId, $this->id ), esc_html__( 'Deselect All', 'gravityforms' ), $this );
$deselect_label = esc_html( $deselect_label );
// Get tabindex.
$tabindex = $this->get_tabindex();
// Prepare choice ID.
$id = 'choice_' . $this->id . '_select_all';
// Prepare choice markup.
$choice_markup = "<li class='gchoice_select_all'>
<input type='checkbox' id='{$id}' {$tabindex} {$disabled_text} onclick='gformToggleCheckboxes( this )' onkeypress='gformToggleCheckboxes( this )' />
<label for='{$id}' id='label_" . $this->id . "_select_all' data-label-select='{$select_label}' data-label-deselect='{$deselect_label}'>{$select_label}</label>
</li>";
/**
* Override the default choice markup used when rendering radio button, checkbox and drop down type fields.
*
* @since 1.9.6
*
* @param string $choice_markup The string containing the choice markup to be filtered.
* @param array $choice An associative array containing the choice properties.
* @param object $field The field currently being processed.
* @param string $value The value to be selected if the field is being populated.
*/
$choices .= gf_apply_filters( array( 'gform_field_choice_markup_pre_render', $this->formId, $this->id ), $choice_markup, array(), $this, $value );
}
// Loop through field choices.
foreach ( $this->choices as $choice ) {
// Hack to skip numbers ending in 0, so that 5.1 doesn't conflict with 5.10.
if ( $choice_number % 10 == 0 ) {
$choice_number ++;
}
// Prepare input ID.
$input_id = $this->id . '.' . $choice_number;
if ( $is_entry_detail || $is_form_editor || $form_id == 0 ) {
$id = $this->id . '_' . $choice_number ++;
} else {
$id = $form_id . '_' . $this->id . '_' . $choice_number ++;
}
if ( ( $is_form_editor || ( ! isset( $_GET['gf_token'] ) && empty( $_POST ) ) ) && rgar( $choice, 'isSelected' ) ) {
$checked = "checked='checked'";
} elseif ( is_array( $value ) && GFFormsModel::choice_value_match( $this, $choice, rgget( $input_id, $value ) ) ) {
$checked = "checked='checked'";
} elseif ( ! is_array( $value ) && GFFormsModel::choice_value_match( $this, $choice, $value ) ) {
$checked = "checked='checked'";
} else {
$checked = '';
}
$tabindex = $this->get_tabindex();
$choice_value = $choice['value'];
if ( $this->enablePrice ) {
$price = rgempty( 'price', $choice ) ? 0 : GFCommon::to_number( rgar( $choice, 'price' ) );
$choice_value .= '|' . $price;
}
$choice_value = esc_attr( $choice_value );
$choice_markup = "<li class='gchoice_{$id}'>
<input name='input_{$input_id}' type='checkbox' value='{$choice_value}' {$checked} id='choice_{$id}' {$tabindex} {$disabled_text} />
<label for='choice_{$id}' id='label_{$id}'>{$choice['text']}</label>
</li>";
/**
* Override the default choice markup used when rendering radio button, checkbox and drop down type fields.
*
* @since 1.9.6
*
* @param string $choice_markup The string containing the choice markup to be filtered.
* @param array $choice An associative array containing the choice properties.
* @param object $field The field currently being processed.
* @param string $value The value to be selected if the field is being populated.
*/
$choices .= gf_apply_filters( array( 'gform_field_choice_markup_pre_render', $this->formId, $this->id ), $choice_markup, $choice, $this, $value );
$is_admin = $is_entry_detail || $is_form_editor;
if ( $is_admin && rgget('view') != 'entry' && $count >= 5 ) {
break;
}
$count ++;
}
$total = sizeof( $this->choices );
if ( $count < $total ) {
$choices .= "<li class='gchoice_total'>" . sprintf( esc_html__( '%d of %d items shown. Edit field to view all', 'gravityforms' ), $count, $total ) . '</li>';
}
}
/**
* Modify the checkbox items before they are added to the checkbox list.
*
* @since Unknown
*
* @param string $choices The string containing the choices to be filtered.
* @param object $field Ahe field currently being processed.
*/
return gf_apply_filters( array( 'gform_field_choices', $this->formId, $this->id ), $choices, $this );
}
/**
* Determine if a specific checkbox is checked.
*
* @since Unknown
* @access public
*
* @param int $field_id Field ID.
* @param string $field_label Field label.
* @param array $entry Entry object.
*
* @return bool
*/
public function is_checkbox_checked( $field_id, $field_label, $entry ) {
$allowed_tags = wp_kses_allowed_html( 'post' );
$entry_field_keys = array_keys( $entry );
// Looping through lead detail values trying to find an item identical to the column label. Mark with a tick if found.
foreach ( $entry_field_keys as $input_id ) {
// Mark as a tick if input label (from form meta) is equal to submitted value (from lead)
if ( is_numeric( $input_id ) && absint( $input_id ) == absint( $field_id ) ) {
$sanitized_value = wp_kses( $entry[ $input_id ], $allowed_tags );
$sanitized_label = wp_kses( $field_label, $allowed_tags );
if ( $sanitized_value == $sanitized_label ) {
return $entry[ $input_id ];
} else {
if ( $this->enableChoiceValue || $this->enablePrice ) {
foreach ( $this->choices as $choice ) {
if ( $choice['value'] == $entry[ $field_id ] ) {
return $choice['value'];
} else if ( $this->enablePrice ) {
$ary = explode( '|', $entry[ $field_id ] );
$val = count( $ary ) > 0 ? $ary[0] : '';
$price = count( $ary ) > 1 ? $ary[1] : '';
if ( $val == $choice['value'] ) {
return $choice['value'];
}
}
}
}
}
}
}
return false;
}
// # OTHER HELPERS --------------------------------------------------------------------------------------------------
/**
* Returns the input ID to be assigned to the field label for attribute.
*
* @since Unknown
* @access public
*
* @param array $form The Form Object currently being processed.
*
* @return string
*/
public function get_first_input_id( $form ) {
return '';
}
/**
* Retrieve the field default value.
*
* @since Unknown
* @access public
*
* @uses GFCommon::replace_variables_prepopulate()
* @uses GF_Field::is_form_editor()
*
* @return array|string
*/
public function get_value_default() {
return $this->is_form_editor() ? $this->defaultValue : GFCommon::replace_variables_prepopulate( $this->defaultValue );
}
// # SANITIZATION ---------------------------------------------------------------------------------------------------
/**
* If the field should allow html tags to be saved with the entry value. Default is false.
*
* @since Unknown
* @access public
*
* @return bool
*/
public function allow_html() {
return true;
}
/**
* Forces settings into expected values while saving the form object.
*
* No escaping should be done at this stage to prevent double escaping on output.
*
* Currently called only for forms created after version 1.9.6.10.
*
* @since Unknown
* @access public
*
*/
public function sanitize_settings() {
parent::sanitize_settings();
if ( 'option' === $this->type ) {
$this->productField = absint( $this->productField );
}
if ( 'post_category' === $this->type ) {
$this->displayAllCategories = (bool) $this->displayAllCategories;
}
}
/**
* Strip scripts and some HTML tags.
*
* @since Unknown
* @access public
*
* @param string $value The field value to be processed.
* @param int $form_id The ID of the form currently being processed.
*
* @uses GF_Field::get_allowable_tags()
*
* @return string
*/
public function sanitize_entry_value( $value, $form_id ) {
// If the value is an array, return an empty string.
if ( is_array( $value ) ) {
return '';
}
// Get allowable tags for field value.
$allowable_tags = $this->get_allowable_tags( $form_id );
// If allowable tags are defined, strip unallowed tags.
if ( $allowable_tags !== true ) {
$value = strip_tags( $value, $allowable_tags );
}
// Sanitize value.
$allowed_protocols = wp_allowed_protocols();
$value = wp_kses_no_null( $value, array( 'slash_zero' => 'keep' ) );
$value = wp_kses_hook( $value, 'post', $allowed_protocols );
$value = wp_kses_split( $value, 'post', $allowed_protocols );
return $value;
}
// # FIELD FILTER UI HELPERS ---------------------------------------------------------------------------------------
/**
* Returns the filter operators for the current field.
*
* @since 2.4
*
* @return array
*/
public function get_filter_operators() {
return array( 'is' );
}
}
GF_Fields::register( new GF_Field_Checkbox() );
class-gf-field-shipping.php 0000666 00000001107 15126403614 0011661 0 ustar 00 <?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Shipping extends GF_Field {
public $type = 'shipping';
function get_form_editor_field_settings() {
return array(
'shipping_field_type_setting',
'conditional_logic_field_setting',
'prepopulate_field_setting',
'label_setting',
'admin_label_setting',
'label_placement_setting',
'description_setting',
'css_class_setting',
);
}
public function get_form_editor_field_title() {
return esc_attr__( 'Shipping', 'gravityforms' );
}
}
GF_Fields::register( new GF_Field_Shipping() );