plugin updates
This commit is contained in:
@@ -9,6 +9,7 @@ if ( ! class_exists( 'GFForms' ) ) {
|
||||
}
|
||||
|
||||
use Gravity_Forms\Gravity_Forms\Settings\Settings;
|
||||
use Gravity_Forms\Gravity_Forms\Settings\GF_Settings_Encryption;
|
||||
use Gravity_Forms\Gravity_Forms\TranslationsPress_Updater;
|
||||
use Gravity_Forms\Gravity_Forms\Save_Form\GF_Save_Form_Service_Provider;
|
||||
use Gravity_Forms\Gravity_Forms\Save_Form\GF_Save_Form_Helper;
|
||||
@@ -78,6 +79,11 @@ abstract class GFAddOn {
|
||||
*/
|
||||
public $app_hook_suffix;
|
||||
|
||||
/**
|
||||
* @var string The '.min' suffix to append to asset files in production mode.
|
||||
*/
|
||||
protected $_asset_min;
|
||||
|
||||
private $_saved_settings = array();
|
||||
private $_previous_settings = array();
|
||||
|
||||
@@ -93,6 +99,13 @@ abstract class GFAddOn {
|
||||
*/
|
||||
private $_setting_field_errors = array();
|
||||
|
||||
/**
|
||||
* Stores the current instance of the Settings encryption class.
|
||||
*
|
||||
* @var \Gravity_Forms\Gravity_Forms\Settings\GF_Settings_Encryption
|
||||
*/
|
||||
private $_encryptor;
|
||||
|
||||
// ------------ Permissions -----------
|
||||
/**
|
||||
* @var string|array A string or an array of capabilities or roles that have access to the settings page
|
||||
@@ -170,6 +183,7 @@ abstract class GFAddOn {
|
||||
* Class constructor which hooks the instance into the WordPress init action
|
||||
*/
|
||||
function __construct() {
|
||||
$this->_asset_min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
|
||||
$this->update_path();
|
||||
$this->bootstrap();
|
||||
|
||||
@@ -189,27 +203,86 @@ abstract class GFAddOn {
|
||||
*/
|
||||
public function bootstrap() {
|
||||
add_action( 'init', array( $this, 'init' ), 15 );
|
||||
if ( $this->_enable_theme_layer ) {
|
||||
|
||||
$is_admin_ajax = defined('DOING_AJAX') && DOING_AJAX;
|
||||
if ( $this->_enable_theme_layer && ! $is_admin_ajax ) {
|
||||
add_action( 'init', array( $this, 'init_theme_layer' ), 0, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the theme layer process for the add-on.
|
||||
*
|
||||
* @since Unknown
|
||||
*
|
||||
*/
|
||||
public function init_theme_layer() {
|
||||
$layer = new Theme_Layer_Builder();
|
||||
$layer->set_name( $this->theme_layer_slug() )
|
||||
->set_short_title( $this->theme_layer_title() )
|
||||
->set_priority( $this->theme_layer_priority() )
|
||||
->set_icon( $this->theme_layer_icon() )
|
||||
->set_settings_fields( $this->theme_layer_settings_fields() )
|
||||
->set_overidden_fields( $this->theme_layer_overridden_fields() )
|
||||
->set_form_css_properties( array( $this, 'theme_layer_form_css_properties' ) )
|
||||
->set_styles( array( $this, 'theme_layer_styles' ) )
|
||||
->set_scripts( array( $this, 'theme_layer_scripts' ) )
|
||||
->set_capability( $this->get_form_settings_capabilities() )
|
||||
->register();
|
||||
->set_short_title( $this->theme_layer_title() )
|
||||
->set_priority( $this->theme_layer_priority() )
|
||||
->set_icon( $this->theme_layer_icon() )
|
||||
->set_settings_fields( $this->theme_layer_settings_fields() )
|
||||
->set_overidden_fields( $this->theme_layer_overridden_fields() )
|
||||
->set_form_css_properties( array( $this, 'theme_layer_form_css_properties' ) )
|
||||
->set_styles( array( $this, 'theme_layer_styles' ) )
|
||||
->set_scripts( array( $this, 'theme_layer_scripts' ) )
|
||||
->set_capability( $this->get_form_settings_capabilities() )
|
||||
->register();
|
||||
add_action( 'gform_form_after_open', array( $this, 'output_third_party_styles' ), 998, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method that returns the theme styles that should be enqueued for the add-on. Returns an array in the format accepted by the Gravity Forms theme layer set_styles() method
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param array $form The current form object to enqueue styles for.
|
||||
* @param string $field_type The field type associated with the add-on. Styles will only be enqueued on the frontend if the form has a field with the specified field type.
|
||||
* @param string $gravity_theme_path The path to the gravity theme style. Optional. Only needed for add-ons that implement the gravity theme outside the default /assets/css/dist/theme.css path.
|
||||
*
|
||||
* @return array Returns and array of styles to enqueue in the format accepted by the Gravity Forms theme layer set_styles() method.
|
||||
*/
|
||||
public function get_theme_layer_styles( $form, $field_type = '', $gravity_theme_path = '' ) {
|
||||
|
||||
$themes = $this->get_themes_to_enqueue( $form, $field_type );
|
||||
$styles = array();
|
||||
|
||||
// Maybe enqueue theme framework.
|
||||
if ( in_array( 'orbital', $themes ) ) {
|
||||
$styles['foundation'] = array(
|
||||
array( "{$this->_slug}_theme_foundation", $this->get_base_url() . "/assets/css/dist/theme-foundation{$this->_asset_min}.css" ),
|
||||
);
|
||||
$styles['framework'] = array(
|
||||
array( "{$this->_slug}_theme_framework", $this->get_base_url() . "/assets/css/dist/theme-framework{$this->_asset_min}.css" ),
|
||||
);
|
||||
}
|
||||
|
||||
// Maybe enqueue gravity theme.
|
||||
if ( in_array( 'gravity-theme', $themes ) ) {
|
||||
$path = $gravity_theme_path ? $gravity_theme_path : $this->get_base_url() . "/assets/css/dist/theme{$this->_asset_min}.css";
|
||||
$styles['theme'] = array(
|
||||
array( "{$this->_slug}_gravity_theme", $path ),
|
||||
);
|
||||
}
|
||||
|
||||
return $styles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method that returns the themes that should be enqueued for the add-on. Returns an array of theme slugs.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param array $form The current form object to enqueue styles for.
|
||||
* @param string|array $field_types The field type(s) associated with the add-on. Themes will only be enqueued on the frontend if the form has a field with the specified field type(s). Can be a string with a single field type or an array of strings with multiple field types.
|
||||
*
|
||||
* @return array Returns and array of theme slugs to enqueue.
|
||||
*/
|
||||
public function get_themes_to_enqueue ( $form, $field_types = '' ) {
|
||||
return \GFFormDisplay::get_themes_to_enqueue( $form, $field_types );
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an addon so that it gets initialized appropriately
|
||||
*
|
||||
@@ -268,6 +341,32 @@ abstract class GFAddOn {
|
||||
return $instances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a registered add-on by its slug and return its instance.
|
||||
*
|
||||
* @since 2.7.17
|
||||
*
|
||||
* @param string $slug The add-on slug.
|
||||
*
|
||||
* @return GFAddOn Returns an instance of the add-on with the specified slug.
|
||||
*/
|
||||
public static function get_addon_by_slug( $slug ) {
|
||||
|
||||
static $map = array();
|
||||
|
||||
if ( isset( $map[ $slug ] ) ) {
|
||||
return $map[ $slug ];
|
||||
}
|
||||
|
||||
$addons = GFAddOn::get_registered_addons( true );
|
||||
|
||||
foreach ( $addons as $addon ) {
|
||||
$map[ $addon->get_slug() ] = $addon;
|
||||
}
|
||||
|
||||
return rgar( $map, $slug );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes all addons.
|
||||
*
|
||||
@@ -1528,7 +1627,7 @@ abstract class GFAddOn {
|
||||
* );
|
||||
* }
|
||||
*
|
||||
* @return array|bool
|
||||
* @return array|bool
|
||||
*/
|
||||
public function get_results_page_config() {
|
||||
return false;
|
||||
@@ -1610,8 +1709,8 @@ abstract class GFAddOn {
|
||||
*/
|
||||
public function members_register_caps() {
|
||||
|
||||
// Get capabilities.
|
||||
$caps = $this->get_members_caps();
|
||||
// Get capabilities.
|
||||
$caps = $this->get_members_caps();
|
||||
|
||||
// If no capabilities were found, exit.
|
||||
if ( empty( $caps ) ) {
|
||||
@@ -2270,7 +2369,7 @@ abstract class GFAddOn {
|
||||
}
|
||||
|
||||
public function has_setting_field_type( $type, $fields ) {
|
||||
if ( ! empty( $fields ) ) {
|
||||
if ( ! empty( $fields ) ) {
|
||||
foreach ( $fields as &$section ) {
|
||||
foreach ( $section['fields'] as $field ) {
|
||||
if ( rgar( $field, 'type' ) == $type ) {
|
||||
@@ -2312,8 +2411,35 @@ abstract class GFAddOn {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current instance of object that handles settings encryption.
|
||||
*
|
||||
* @since 2.7.17
|
||||
*
|
||||
* @param \Gravity_Forms\Gravity_Forms\Settings\GF_Settings_Encryption $encryptor Settings encryptor.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set_encryptor( $encryptor ) {
|
||||
$this->_encryptor = $encryptor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current instance of the settings encryptor.
|
||||
*
|
||||
* @since 2.7.17
|
||||
*
|
||||
* @return GF_Settings_Encryption Returns the current instance of the settings encryptor.
|
||||
*/
|
||||
public function get_encryptor() {
|
||||
if ( ! $this->_encryptor ) {
|
||||
require_once( GFCommon::get_base_path() . '/includes/settings/class-gf-settings-encryption.php' );
|
||||
$this->_encryptor = new GF_Settings_Encryption();
|
||||
}
|
||||
return $this->_encryptor;
|
||||
}
|
||||
|
||||
//------------- Field Types ------------------------------------------------------
|
||||
|
||||
/***
|
||||
@@ -3128,7 +3254,7 @@ abstract class GFAddOn {
|
||||
}
|
||||
}
|
||||
|
||||
return $fields;
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3806,11 +3932,11 @@ abstract class GFAddOn {
|
||||
$error = $this->get_field_errors( $field );
|
||||
|
||||
return '<span
|
||||
class="gf_tooltip tooltip"
|
||||
title="<h6>' . esc_html__( 'Validation Error', 'gravityforms' ) . '</h6>' . $error . '"
|
||||
style="display:inline-block;position:relative;right:-3px;top:1px;font-size:14px;">
|
||||
<i class="fa fa-exclamation-circle icon-exclamation-sign gf_invalid"></i>
|
||||
</span>';
|
||||
class="gf_tooltip tooltip"
|
||||
title="<h6>' . esc_html__( 'Validation Error', 'gravityforms' ) . '</h6>' . $error . '"
|
||||
style="display:inline-block;position:relative;right:-3px;top:1px;font-size:14px;">
|
||||
<i class="fa fa-exclamation-circle icon-exclamation-sign gf_invalid"></i>
|
||||
</span>';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4771,6 +4897,7 @@ abstract class GFAddOn {
|
||||
'fields' => $sections,
|
||||
'initial_values' => $this->get_plugin_settings(),
|
||||
'save_callback' => array( $this, 'update_plugin_settings' ),
|
||||
'field_encryption_disabled' => true,
|
||||
)
|
||||
);
|
||||
|
||||
@@ -4890,15 +5017,30 @@ abstract class GFAddOn {
|
||||
return $this->method_is_overridden( 'plugin_settings_fields' ) || $this->method_is_overridden( 'plugin_settings_page' ) || $this->method_is_overridden( 'plugin_settings' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array Holds the cached plugin settings.
|
||||
*
|
||||
* @since 2.7.17
|
||||
*/
|
||||
private static $_plugin_settings = array();
|
||||
|
||||
/**
|
||||
* Returns the currently saved plugin settings
|
||||
*
|
||||
* @since Unknown
|
||||
*
|
||||
* @return array|false
|
||||
* @since 2.7.17 Added caching of plugin settings and encrypting of settings.
|
||||
*
|
||||
* @return array|false Returns the plugin settings or false if the settings haven't been saved yet.
|
||||
*/
|
||||
public function get_plugin_settings() {
|
||||
return get_option( 'gravityformsaddon_' . $this->get_slug() . '_settings' );
|
||||
if ( isset( self::$_plugin_settings[ $this->get_slug() ] ) ) {
|
||||
return self::$_plugin_settings[$this->get_slug() ];
|
||||
}
|
||||
|
||||
self::$_plugin_settings[ $this->get_slug() ] = $this->get_encryptor()->decrypt( get_option( 'gravityformsaddon_' . $this->get_slug() . '_settings' ) );
|
||||
|
||||
return self::$_plugin_settings[ $this->get_slug() ];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4915,7 +5057,6 @@ abstract class GFAddOn {
|
||||
|
||||
$settings = $this->get_plugin_settings();
|
||||
return isset( $settings[ $setting_name ] ) ? $settings[ $setting_name ] : null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4923,10 +5064,14 @@ abstract class GFAddOn {
|
||||
*
|
||||
* @since Unknown
|
||||
*
|
||||
* @since 2.7.17 Added caching of plugin settings and encrypting of settings.
|
||||
*
|
||||
* @param array $settings Plugin settings to be saved.
|
||||
*/
|
||||
public function update_plugin_settings( $settings ) {
|
||||
update_option( 'gravityformsaddon_' . $this->get_slug() . '_settings', $settings );
|
||||
|
||||
self::$_plugin_settings[$this->get_slug() ] = $settings;
|
||||
update_option( 'gravityformsaddon_' . $this->get_slug() . '_settings', $this->get_encryptor()->encrypt( $settings ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -634,6 +634,16 @@ abstract class GFFeedAddOn extends GFAddOn {
|
||||
|
||||
//-------- Feed data methods -------------------------
|
||||
|
||||
/**
|
||||
* Gets the feeds for the specified form id.
|
||||
*
|
||||
* @since Unknown
|
||||
* @since 2.7.17 Added support for decrypting settings fields.
|
||||
*
|
||||
* @param int $form_id The form id to get feeds for.
|
||||
*
|
||||
* @return array Returns an array of feeds for the specified form id.
|
||||
*/
|
||||
public function get_feeds( $form_id = null ) {
|
||||
global $wpdb;
|
||||
|
||||
@@ -646,7 +656,7 @@ abstract class GFFeedAddOn extends GFAddOn {
|
||||
|
||||
$results = $wpdb->get_results( $sql, ARRAY_A );
|
||||
foreach ( $results as &$result ) {
|
||||
$result['meta'] = json_decode( $result['meta'], true );
|
||||
$result['meta'] = $this->decrypt_feed_meta( json_decode( $result['meta'], true ) );
|
||||
}
|
||||
|
||||
return $results;
|
||||
@@ -656,6 +666,7 @@ abstract class GFFeedAddOn extends GFAddOn {
|
||||
* Queries and returns all active feeds for this Add-On
|
||||
*
|
||||
* @since 2.4
|
||||
* @since 2.7.17 Added support for decrypting settings fields.
|
||||
*
|
||||
* @param int $form_id The Form Id to get feeds from.
|
||||
*
|
||||
@@ -673,12 +684,23 @@ abstract class GFFeedAddOn extends GFAddOn {
|
||||
|
||||
$results = $wpdb->get_results( $sql, ARRAY_A );
|
||||
foreach ( $results as &$result ) {
|
||||
$result['meta'] = json_decode( $result['meta'], true );
|
||||
$result['meta'] = $this->decrypt_feed_meta( json_decode( $result['meta'], true ) );
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the feeds for the specified addon slug and form id.
|
||||
*
|
||||
* @since Unknown
|
||||
* @since 2.7.17 Added support for decrypting settings fields.
|
||||
*
|
||||
* @param string $slug The addon slug to get feeds for.
|
||||
* @param int $form_id (optional) The form id to get feeds for. If not specified, all feeds for the specified addon slug will be returned.
|
||||
*
|
||||
* @return array Returns an array of feeds for the specified form id.
|
||||
*/
|
||||
public function get_feeds_by_slug( $slug, $form_id = null ) {
|
||||
global $wpdb;
|
||||
|
||||
@@ -694,7 +716,7 @@ abstract class GFFeedAddOn extends GFAddOn {
|
||||
|
||||
$results = $wpdb->get_results( $sql, ARRAY_A );
|
||||
foreach( $results as &$result ) {
|
||||
$result['meta'] = json_decode( $result['meta'], true );
|
||||
$result['meta'] = $this->decrypt_feed_meta( json_decode( $result['meta'], true ) );
|
||||
}
|
||||
|
||||
return $results;
|
||||
@@ -716,6 +738,16 @@ abstract class GFFeedAddOn extends GFAddOn {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a feed by its id.
|
||||
*
|
||||
* @since Unknown
|
||||
* @since 2.7.17 Added support for decrypting settings fields.
|
||||
*
|
||||
* @param int $id The feed id.
|
||||
*
|
||||
* @return array Returns the feed array if found, false otherwise.
|
||||
*/
|
||||
public function get_feed( $id ) {
|
||||
global $wpdb;
|
||||
|
||||
@@ -731,7 +763,7 @@ abstract class GFFeedAddOn extends GFAddOn {
|
||||
return false;
|
||||
}
|
||||
|
||||
$row['meta'] = json_decode( $row['meta'], true );
|
||||
$row['meta'] = $this->decrypt_feed_meta( json_decode( $row['meta'], true ) );
|
||||
|
||||
return $row;
|
||||
}
|
||||
@@ -772,6 +804,20 @@ abstract class GFFeedAddOn extends GFAddOn {
|
||||
return $meets_conditional_logic ? false : $has_active_feed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts the feed meta row and return the decripted array.
|
||||
*
|
||||
* @since 2.7.17
|
||||
*
|
||||
* @param array $row The feed meta row to decrypt.
|
||||
*
|
||||
* @return array Returns the feed meta row with values decrypted appropriately.
|
||||
*/
|
||||
private function decrypt_feed_meta( $row ) {
|
||||
|
||||
return $this->get_encryptor()->decrypt_feed_meta( $row );
|
||||
}
|
||||
|
||||
public function get_single_submission_feed( $entry = false, $form = false ) {
|
||||
|
||||
if ( ! $entry && ! $form ) {
|
||||
@@ -779,26 +825,18 @@ abstract class GFFeedAddOn extends GFAddOn {
|
||||
}
|
||||
|
||||
$feed = false;
|
||||
|
||||
if ( ! empty( $this->_single_submission_feed ) && ( ! $form || $this->_single_submission_feed['form_id'] == $form['id'] ) ) {
|
||||
|
||||
$feed = $this->_single_submission_feed;
|
||||
|
||||
} elseif ( ! empty( $entry['id'] ) ) {
|
||||
|
||||
$feeds = $this->get_feeds_by_entry( $entry['id'] );
|
||||
|
||||
if ( empty( $feeds ) ) {
|
||||
$feed = $this->get_single_submission_feed_by_form( $form, $entry );
|
||||
} else {
|
||||
$feed = $this->get_feed( $feeds[0] );
|
||||
}
|
||||
|
||||
} elseif ( $form ) {
|
||||
|
||||
$feed = $this->get_single_submission_feed_by_form( $form, $entry );
|
||||
$this->_single_submission_feed = $feed;
|
||||
|
||||
}
|
||||
|
||||
return $feed;
|
||||
@@ -924,9 +962,23 @@ abstract class GFFeedAddOn extends GFAddOn {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the feed meta
|
||||
*
|
||||
* @since Unknown
|
||||
*
|
||||
* @since 2.7.17 Added support for encrypting of settings fields.
|
||||
*
|
||||
* @param int $id Feed ID
|
||||
* @param array $meta Feed meta to be updated
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function update_feed_meta( $id, $meta ) {
|
||||
global $wpdb;
|
||||
|
||||
$meta = $this->get_encryptor()->encrypt_feed_meta( $meta, $this->get_fields_to_encrypt() );
|
||||
|
||||
$meta = json_encode( $meta );
|
||||
$wpdb->update( "{$wpdb->prefix}gf_addon_feed", array( 'meta' => $meta ), array( 'id' => $id ), array( '%s' ), array( '%d' ) );
|
||||
|
||||
@@ -942,6 +994,19 @@ abstract class GFFeedAddOn extends GFAddOn {
|
||||
return $wpdb->rows_affected > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a new feed record.
|
||||
*
|
||||
* @since Unknown
|
||||
*
|
||||
* @since 2.7.17 Added support for encrypting settings fields.
|
||||
*
|
||||
* @param int $form_id Form ID.
|
||||
* @param bool $is_active If the feed is active or not.
|
||||
* @param array $meta Feed meta
|
||||
*
|
||||
* @return false|int Returns the ID of the newly created feed or false if the feed table does not exist.
|
||||
*/
|
||||
public function insert_feed( $form_id, $is_active, $meta ) {
|
||||
global $wpdb;
|
||||
|
||||
@@ -950,12 +1015,47 @@ abstract class GFFeedAddOn extends GFAddOn {
|
||||
return false;
|
||||
}
|
||||
|
||||
$meta = $this->get_encryptor()->encrypt_feed_meta( $meta, $this->get_fields_to_encrypt() );
|
||||
|
||||
$meta = json_encode( $meta );
|
||||
$wpdb->insert( "{$wpdb->prefix}gf_addon_feed", array( 'addon_slug' => $this->get_slug(), 'form_id' => $form_id, 'is_active' => $is_active, 'meta' => $meta ), array( '%s', '%d', '%d', '%s' ) );
|
||||
|
||||
return $wpdb->insert_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array of feed settings field names that are configured to be encrypted.
|
||||
*
|
||||
* @since 2.7.16
|
||||
*
|
||||
* @return array Returns an array with all field names that are configured to be encrypted.
|
||||
*/
|
||||
public function get_fields_to_encrypt() {
|
||||
|
||||
static $cached_fields_to_encrypt;
|
||||
if ( rgar( $cached_fields_to_encrypt, $this->_slug ) ) {
|
||||
return $cached_fields_to_encrypt[ $this->_slug ];
|
||||
}
|
||||
|
||||
$groups = $this->get_feed_settings_fields();
|
||||
|
||||
// Loop through feed settings fields and create array of fields that are configured to be encrypted
|
||||
$fields_to_encrypt = array();
|
||||
foreach ( $groups as $group ) {
|
||||
if ( ! isset( $group['fields'] ) ) {
|
||||
continue;
|
||||
}
|
||||
foreach ( $group['fields'] as $field ) {
|
||||
if ( rgar( $field, 'encrypt' ) ) {
|
||||
$fields_to_encrypt[] = $field['name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
$cached_fields_to_encrypt[ $this->_slug ] = $fields_to_encrypt;
|
||||
|
||||
return $fields_to_encrypt;
|
||||
}
|
||||
|
||||
public function delete_feed( $id ) {
|
||||
global $wpdb;
|
||||
|
||||
@@ -1390,11 +1490,17 @@ abstract class GFFeedAddOn extends GFAddOn {
|
||||
|
||||
},
|
||||
'before_fields' => function() use ( $form ) {
|
||||
$script = sprintf( 'var form = %s;', wp_json_encode( $form ) );
|
||||
$entry_meta = $this->get_feed_settings_entry_meta( $form );
|
||||
if ( ! empty( $entry_meta ) ) {
|
||||
$script .= sprintf( 'var entry_meta = %s;', wp_json_encode( $entry_meta ) );
|
||||
}
|
||||
|
||||
return sprintf( '
|
||||
<input type="hidden" name="gf_feed_id" value="%d" />
|
||||
<script type="text/javascript">var form = %s;</script>',
|
||||
%s',
|
||||
(int) $this->get_current_feed_id(),
|
||||
wp_json_encode( $form )
|
||||
GFCommon::get_inline_script_tag( $script, false )
|
||||
);
|
||||
},
|
||||
)
|
||||
@@ -1439,6 +1545,29 @@ abstract class GFFeedAddOn extends GFAddOn {
|
||||
$this->get_settings_renderer()->process_postback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of entry meta fields to be assigned to the JavaScript entry_meta variable used by the feed condition setting.
|
||||
*
|
||||
* @since 2.9
|
||||
*
|
||||
* @param array $form The form the feed is being created or edited for.
|
||||
* @param array $entry_meta An empty array or the entry meta fields to be assigned to the JavaScript entry_meta variable.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_feed_settings_entry_meta( $form, $entry_meta = array() ) {
|
||||
/**
|
||||
* Allows population of the JavaScript entry_meta variable on the feed configuration page.
|
||||
*
|
||||
* @since 2.9
|
||||
*
|
||||
* @param array $entry_meta An empty array or the entry meta fields to be assigned to the JavaScript entry_meta variable.
|
||||
* @param array $form The form the feed is being created or edited for.
|
||||
* @param GFFeedAddOn $addon The current add-on instance.
|
||||
*/
|
||||
return apply_filters( 'gform_entry_meta_pre_render_feed_settings', $entry_meta, $form, $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render feed edit page.
|
||||
*
|
||||
|
||||
@@ -2152,10 +2152,12 @@ abstract class GFPaymentAddOn extends GFFeedAddOn {
|
||||
|
||||
// keep 'gform_subscription_payment_failed' for backward compatability
|
||||
/**
|
||||
* @deprecated Use gform_post_fail_subscription_payment now
|
||||
* @deprecated Use gform_post_fail_subscription_payment now.
|
||||
* @remove-in 3.0
|
||||
*/
|
||||
do_action( 'gform_subscription_payment_failed', $entry, $action['subscription_id'] );
|
||||
if ( has_filter( 'gform_subscription_payment_failed' ) ) {
|
||||
trigger_error( 'gform_subscription_payment_failed is deprecated and will be removed in version 3.0. Use gform_post_fail_subscription_payment.', E_USER_DEPRECATED );
|
||||
$this->log_debug( __METHOD__ . '(): Executing functions hooked to gform_subscription_payment_failed.' );
|
||||
}
|
||||
/**
|
||||
@@ -2374,6 +2376,20 @@ abstract class GFPaymentAddOn extends GFFeedAddOn {
|
||||
|
||||
//--------- Feed Settings ----------------
|
||||
|
||||
/**
|
||||
* Returning an empty array because payment feed logic is evaluated before entry meta is saved.
|
||||
*
|
||||
* @since 2.9
|
||||
*
|
||||
* @param array $form The form the feed is being created or edited for.
|
||||
* @param array $entry_meta An empty array or the entry meta fields to be assigned to the JavaScript entry_meta variable.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_feed_settings_entry_meta( $form, $entry_meta = array() ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the add new button from the title if the form requires a credit card field.
|
||||
*
|
||||
|
||||
@@ -36,6 +36,10 @@ var GFFrontendFeeds = function( args ) {
|
||||
|
||||
};
|
||||
|
||||
self.saveToState = function() {
|
||||
gform.state.set( self.options.formId, 'feeds', self.options.feeds );
|
||||
}
|
||||
|
||||
self.evaluateFeeds = function() {
|
||||
|
||||
var feed, isMatch, isActivated;
|
||||
@@ -67,6 +71,7 @@ var GFFrontendFeeds = function( args ) {
|
||||
gform.doAction( 'gform_{0}_frontend_feeds_evaluated'.gformFormat( feed.addonSlug ), self.options.feeds, self.options.formId, self );
|
||||
gform.doAction( 'gform_{0}_frontend_feeds_evaluated_{0}'.gformFormat( feed.addonSlug, self.options.formId ), self.options.feeds, self.options.formId, self );
|
||||
|
||||
self.saveToState();
|
||||
};
|
||||
|
||||
self.evaluateFeed = function( feed, formId ) {
|
||||
|
||||
@@ -1 +1 @@
|
||||
var GFFrontendFeeds=function(o){var r=this,f=jQuery;r.init=function(){r.options=o,r.triggerInputIds=r.getTriggerInputIds(r.options.feeds),r.activeFeeds=[],r.evaluateFeeds(),r.bindEvents()},r.bindEvents=function(){gform.addAction("gform_input_change",function(o,e,t){var d=parseInt(t)+"",t=-1!==f.inArray(t,r.triggerInputIds)||-1!==f.inArray(d,r.triggerInputIds);r.options.formId==e&&t&&r.evaluateFeeds()})},r.evaluateFeeds=function(){var o,e,t;for(i=0;i<r.options.feeds.length;i++)o=r.options.feeds[i],e=r.evaluateFeed(o,r.options.formId),t=r.isFeedActivated(o),e||null===t?e&&!t&&(!o.isSingleFeed||o.isSingleFeed&&r.hasPriority(o.feedId,o.addonSlug))&&r.activateFeed(o):r.deactivateFeed(o);gform.doAction("gform_frontend_feeds_evaluated",r.options.feeds,r.options.formId,r),gform.doAction("gform_frontend_feeds_evaluated_{0}".gformFormat(r.options.formId),r.options.feeds,r.options.formId,r),gform.doAction("gform_{0}_frontend_feeds_evaluated".gformFormat(o.addonSlug),r.options.feeds,r.options.formId,r),gform.doAction("gform_{0}_frontend_feeds_evaluated_{0}".gformFormat(o.addonSlug,r.options.formId),r.options.feeds,r.options.formId,r)},r.evaluateFeed=function(o,e){return!o.conditionalLogic||"show"==gf_get_field_action(e,o.conditionalLogic)},r.getTriggerInputIds=function(){for(var o=[],e=0;e<r.options.feeds.length;e++){var t=r.options.feeds[e];if(t.conditionalLogic)for(var d=0;d<t.conditionalLogic.rules.length;d++){var n=r.options.feeds[e].conditionalLogic.rules[d];-1==f.inArray(n.fieldId,o)&&o.push(n.fieldId)}}return o},r.isFeedActivated=function(o){return!("object"!=typeof o&&!(o=r.getFeed(o)))&&(void 0!==o.isActivated?o.isActivated:null)},r.getFeed=function(o){for(var e=0;e<r.options.feeds.length;e++){var t=r.options.feeds[e];if(t.feedId==o)return t}return!1},r.getFeedsByAddon=function(o,e,t){for(var d=[],n=0;n<r.options.feeds.length;n++){var i=r.options.feeds[n];i.addonSlug!=o||e&&i.feedId==e.feedId||t&&!r.isFeedActivated(i)||d.push(i)}return d},r.activateFeed=function(o){o.feedId&&(o=[o]);for(var e=0;e<o.length;e++){var t=o[e];t.isActivated=!0,gform.doAction("gform_frontend_feed_activated",t,r.options.formId),gform.doAction("gform_frontend_feed_activated_{0}".gformFormat(r.options.formId),t,r.options.formId),gform.doAction("gform_{0}_frontend_feed_activated".gformFormat(t.addonSlug),t,r.options.formId),gform.doAction("gform_{0}_frontend_feed_activated_{0}".gformFormat(t.addonSlug,r.options.formId),t,r.options.formId),t.isSingleFeed&&r.deactivateFeed(r.getFeedsByAddon(t.addonSlug,t))}},r.deactivateFeed=function(o){o.feedId&&(o=[o]);for(var e=0;e<o.length;e++){var t=o[e],d=r.isFeedActivated(t);null!==d&&!1!==d&&(t.isActivated=!1,gform.doAction("gform_frontend_feed_deactivated",t,r.options.formId),gform.doAction("gform_frontend_feed_deactivated_{0}".gformFormat(r.options.formId),t,r.options.formId),gform.doAction("gform_{0}_frontend_feed_deactivated".gformFormat(t.addonSlug),t,r.options.formId),gform.doAction("gform_{0}_frontend_feed_deactivated_{0}".gformFormat(t.addonSlug,r.options.formId),t,r.options.formId))}},r.hasPriority=function(o,e){for(var t=r.getFeedsByAddon(e),d=0;d<=t.length;d++){var n=t[d];if(n.feedId!=o&&n.isActivated)return!1;if(n.feedId==o)return!0}return!1},this.init()};
|
||||
var GFFrontendFeeds=function(o){var r=this,f=jQuery;r.init=function(){r.options=o,r.triggerInputIds=r.getTriggerInputIds(r.options.feeds),r.activeFeeds=[],r.evaluateFeeds(),r.bindEvents()},r.bindEvents=function(){gform.addAction("gform_input_change",function(o,e,t){var d=parseInt(t)+"",t=-1!==f.inArray(t,r.triggerInputIds)||-1!==f.inArray(d,r.triggerInputIds);r.options.formId==e&&t&&r.evaluateFeeds()})},r.saveToState=function(){gform.state.set(r.options.formId,"feeds",r.options.feeds)},r.evaluateFeeds=function(){var o,e,t;for(i=0;i<r.options.feeds.length;i++)o=r.options.feeds[i],e=r.evaluateFeed(o,r.options.formId),t=r.isFeedActivated(o),e||null===t?!e||t||o.isSingleFeed&&(o.isSingleFeed,!r.hasPriority(o.feedId,o.addonSlug))||r.activateFeed(o):r.deactivateFeed(o);gform.doAction("gform_frontend_feeds_evaluated",r.options.feeds,r.options.formId,r),gform.doAction("gform_frontend_feeds_evaluated_{0}".gformFormat(r.options.formId),r.options.feeds,r.options.formId,r),gform.doAction("gform_{0}_frontend_feeds_evaluated".gformFormat(o.addonSlug),r.options.feeds,r.options.formId,r),gform.doAction("gform_{0}_frontend_feeds_evaluated_{0}".gformFormat(o.addonSlug,r.options.formId),r.options.feeds,r.options.formId,r),r.saveToState()},r.evaluateFeed=function(o,e){return!o.conditionalLogic||"show"==gf_get_field_action(e,o.conditionalLogic)},r.getTriggerInputIds=function(){for(var o=[],e=0;e<r.options.feeds.length;e++){var t=r.options.feeds[e];if(t.conditionalLogic)for(var d=0;d<t.conditionalLogic.rules.length;d++){var n=r.options.feeds[e].conditionalLogic.rules[d];-1==f.inArray(n.fieldId,o)&&o.push(n.fieldId)}}return o},r.isFeedActivated=function(o){return!("object"!=typeof o&&!(o=r.getFeed(o)))&&(void 0!==o.isActivated?o.isActivated:null)},r.getFeed=function(o){for(var e=0;e<r.options.feeds.length;e++){var t=r.options.feeds[e];if(t.feedId==o)return t}return!1},r.getFeedsByAddon=function(o,e,t){for(var d=[],n=0;n<r.options.feeds.length;n++){var i=r.options.feeds[n];i.addonSlug!=o||e&&i.feedId==e.feedId||t&&!r.isFeedActivated(i)||d.push(i)}return d},r.activateFeed=function(o){o.feedId&&(o=[o]);for(var e=0;e<o.length;e++){var t=o[e];t.isActivated=!0,gform.doAction("gform_frontend_feed_activated",t,r.options.formId),gform.doAction("gform_frontend_feed_activated_{0}".gformFormat(r.options.formId),t,r.options.formId),gform.doAction("gform_{0}_frontend_feed_activated".gformFormat(t.addonSlug),t,r.options.formId),gform.doAction("gform_{0}_frontend_feed_activated_{0}".gformFormat(t.addonSlug,r.options.formId),t,r.options.formId),t.isSingleFeed&&r.deactivateFeed(r.getFeedsByAddon(t.addonSlug,t))}},r.deactivateFeed=function(o){o.feedId&&(o=[o]);for(var e=0;e<o.length;e++){var t=o[e],d=r.isFeedActivated(t);null!==d&&!1!==d&&(t.isActivated=!1,gform.doAction("gform_frontend_feed_deactivated",t,r.options.formId),gform.doAction("gform_frontend_feed_deactivated_{0}".gformFormat(r.options.formId),t,r.options.formId),gform.doAction("gform_{0}_frontend_feed_deactivated".gformFormat(t.addonSlug),t,r.options.formId),gform.doAction("gform_{0}_frontend_feed_deactivated_{0}".gformFormat(t.addonSlug,r.options.formId),t,r.options.formId))}},r.hasPriority=function(o,e){for(var t=r.getFeedsByAddon(e),d=0;d<=t.length;d++){var n=t[d];if(n.feedId!=o&&n.isActivated)return!1;if(n.feedId==o)return!0}return!1},this.init()};
|
||||
@@ -1 +1 @@
|
||||
window.GFToken=null,function(n){GFToken=function(i){for(var t in i)i.hasOwnProperty(t)&&(this[t]=i[t]);this.form=n("#gform_"+this.formId),this.init=function(){var s=this;this.tokens={},this.isAjax||gformInitSpinner(this.formId),this.hasPages&&n(document).bind("gform_page_loaded",function(i,t,e){t==s.formId&&e!=s.pageCount&&s.saveEntryData()}),this.form.submit(function(){s.onSubmit()})},this.onSubmit=function(){this.form.data("gftokensubmitting")||(event.preventDefault(),this.form.data("gftokensubmitting",!0),this.saveEntryData(),this.processTokens())},this.processTokens=function(){for(var i in this.feeds){this.active_feed=this.feeds[i];var t,e={billing_fields:{},id:this.active_feed.id,name:this.active_feed.name};for(t in this.active_feed.billing_fields)field_id=this.active_feed.billing_fields[t],e.billing_fields[t]=this.entry_data[field_id];window[this.callback].createToken(e,this)}},this.saveEntryData=function(){var t=this,e="input_"+this.formId+"_";this.entry_data||(this.entry_data={}),this.form.find('input[id^="'+e+'"], select[id^="'+e+'"], textarea[id^="'+e+'"]').each(function(){var i=n(this).attr("id").replace(e,"").replace("_",".");0<=n.inArray(i,t.fields)&&(t.entry_data[i]=n(this).val())})},this.saveToken=function(i){this.tokens[this.active_feed.id]={feed_id:this.active_feed.id,response:i},this.tokens.length==this.feeds.length&&(this.form.find(this.responseField).val(n.toJSON(this.tokens)),this.form.submit())},this.init()}}(jQuery);
|
||||
window.GFToken=null,(n=>{GFToken=function(i){for(var t in i)i.hasOwnProperty(t)&&(this[t]=i[t]);this.form=n("#gform_"+this.formId),this.init=function(){var s=this;this.tokens={},this.isAjax||gformInitSpinner(this.formId),this.hasPages&&n(document).bind("gform_page_loaded",function(i,t,e){t==s.formId&&e!=s.pageCount&&s.saveEntryData()}),this.form.submit(function(){s.onSubmit()})},this.onSubmit=function(){this.form.data("gftokensubmitting")||(event.preventDefault(),this.form.data("gftokensubmitting",!0),this.saveEntryData(),this.processTokens())},this.processTokens=function(){for(var i in this.feeds){this.active_feed=this.feeds[i];var t,e={billing_fields:{},id:this.active_feed.id,name:this.active_feed.name};for(t in this.active_feed.billing_fields)field_id=this.active_feed.billing_fields[t],e.billing_fields[t]=this.entry_data[field_id];window[this.callback].createToken(e,this)}},this.saveEntryData=function(){var t=this,e="input_"+this.formId+"_";this.entry_data||(this.entry_data={}),this.form.find('input[id^="'+e+'"], select[id^="'+e+'"], textarea[id^="'+e+'"]').each(function(){var i=n(this).attr("id").replace(e,"").replace("_",".");0<=n.inArray(i,t.fields)&&(t.entry_data[i]=n(this).val())})},this.saveToken=function(i){this.tokens[this.active_feed.id]={feed_id:this.active_feed.id,response:i},this.tokens.length==this.feeds.length&&(this.form.find(this.responseField).val(n.toJSON(this.tokens)),this.form.submit())},this.init()}})(jQuery);
|
||||
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
/**
|
||||
* Handles AJAX services such as validation and submission.
|
||||
*
|
||||
* @package Gravity_Forms\Gravity_Forms\Ajax
|
||||
*/
|
||||
namespace Gravity_Forms\Gravity_Forms\Ajax;
|
||||
|
||||
/**
|
||||
* Class GF_Ajax_Handler
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* Provides functionality for handling AJAX validation and submission.
|
||||
*/
|
||||
class GF_Ajax_Handler {
|
||||
|
||||
/**
|
||||
* Handles the form validation AJAX requests. Uses the global $_POST array and sends the form validation result as a JSON response.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
public function validate_form() {
|
||||
|
||||
// Check nonce.
|
||||
$nonce_result = check_ajax_referer( 'gform_ajax_submission', 'gform_ajax_nonce', false );
|
||||
|
||||
if ( ! $nonce_result ) {
|
||||
wp_send_json_error( $this->nonce_validation_message() );
|
||||
}
|
||||
|
||||
$form_id = absint( rgpost( 'form_id' ) );
|
||||
$target_page = absint( rgpost( 'gform_target_page_number_' . $form_id ) );
|
||||
$source_page = absint( rgpost( 'gform_source_page_number_' . $form_id ) );
|
||||
|
||||
$result = \GFAPI::validate_form( $form_id, array(), rgpost( 'gform_field_values' ), $target_page, $source_page );
|
||||
if ( is_wp_error( $result ) ) {
|
||||
wp_send_json_error( $result->get_error_message() );
|
||||
}
|
||||
|
||||
$form = $result['form'];
|
||||
if ( ! $result['is_valid'] ) {
|
||||
$result = $this->add_validation_summary( $form, $result );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the form validation result.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param array $result The form validation result to be filtered.
|
||||
*
|
||||
* @return array The filtered form validation result.
|
||||
*/
|
||||
$result = gf_apply_filters( array( 'gform_ajax_validation_result', $form['id'] ), $result );
|
||||
|
||||
// Remove form from result.
|
||||
unset( $result['form'] );
|
||||
|
||||
wp_send_json_success( $result );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the form submission AJAX requests. Uses the global $_POST array and sends the form submission result as a JSON response.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
public function submit_form() {
|
||||
|
||||
// Check nonce.
|
||||
$nonce_result = check_ajax_referer( 'gform_ajax_submission', 'gform_ajax_nonce', false );
|
||||
|
||||
if ( ! $nonce_result ) {
|
||||
wp_send_json_error( $this->nonce_validation_message() );
|
||||
}
|
||||
|
||||
$form_id = absint( rgpost( 'form_id' ) );
|
||||
|
||||
/**
|
||||
* Allows actions to be performed right before an AJAX form submission.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param int $form_id The form ID.
|
||||
*/
|
||||
gf_do_action( array( 'gform_ajax_pre_submit_form', $form_id ), $form_id );
|
||||
|
||||
// Handling the save link submission.
|
||||
if ( isset( $_POST['gform_send_resume_link'] ) ) {
|
||||
$this->submit_save_link();
|
||||
return;
|
||||
}
|
||||
|
||||
$target_page = absint( rgpost( 'gform_target_page_number_' . $form_id ) );
|
||||
$source_page = absint( rgpost( 'gform_source_page_number_' . $form_id ) );
|
||||
|
||||
$result = \GFAPI::submit_form( $form_id, array(), rgpost( 'gform_field_values' ), $target_page, $source_page );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
wp_send_json_error( $result->get_error_message() );
|
||||
}
|
||||
|
||||
$form = $result['form'];
|
||||
|
||||
// Adding validation markup if form failed validation
|
||||
if ( ! $result['is_valid'] ) {
|
||||
$result = $this->add_validation_summary( $form, $result );
|
||||
}
|
||||
|
||||
// Adding confirmation markup if there is a confirmation message to be displayed.
|
||||
if ( rgar( $result, 'confirmation_type' ) == 'message' && ! empty( rgar( $result, 'confirmation_message' ) ) ) {
|
||||
$result['confirmation_markup'] = \GFFormDisplay::get_form( $form_id, false, false, false, rgpost( 'gform_field_values' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the ajax form submission result.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param array $result The form submission result to be filtered.
|
||||
*
|
||||
* @return array The filtered form submission result.
|
||||
*/
|
||||
$result = gf_apply_filters( array( 'gform_ajax_submission_result', $form_id ), $result );
|
||||
|
||||
// Remove form from result.
|
||||
unset( $result['form'] );
|
||||
|
||||
wp_send_json_success( $result );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles the save link submission. Uses the $_POST array and sends the save link result as a JSON response.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function submit_save_link() {
|
||||
$form_id = absint( rgpost( 'form_id' ) );
|
||||
|
||||
\GFFormDisplay::process_send_resume_link();
|
||||
|
||||
$confirmation = \GFFormDisplay::get_form( $form_id, false, false, false, rgpost( 'gform_field_values' ) );
|
||||
|
||||
wp_send_json_success(
|
||||
array(
|
||||
'is_valid' => true,
|
||||
'confirmation_type' => 'message',
|
||||
'confirmation_message' => $confirmation,
|
||||
'confirmation_markup' => $confirmation,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the lifespan of the nonce used for AJAX submissions and validation.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param int $lifespan_in_seconds The lifespan of the nonce in seconds. Defaults to 3 days
|
||||
* @param string $action The nonce action (gform_ajax_submission or gform_ajax_validation).
|
||||
*
|
||||
* @return int The filtered lifespan of the nonce in seconds.
|
||||
*/
|
||||
public function nonce_life( $lifespan_in_seconds, $action = '' ) {
|
||||
if ( in_array( $action, array( 'gform_ajax_submission', 'gform_ajax_validation' ) ) ) {
|
||||
|
||||
/**
|
||||
* Filters the lifespan of the nonce used for AJAX submissions and validation.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param int $lifespan_in_seconds The lifespan of the nonce in seconds (defaults to 3 days).
|
||||
* @param string $action The nonce action (gform_ajax_submission or gform_ajax_validation).
|
||||
*
|
||||
* @return int The lifespan of the nonce in seconds.
|
||||
*/
|
||||
$lifespan_in_seconds = apply_filters( 'gform_nonce_life', 3 * DAY_IN_SECONDS, $action );
|
||||
}
|
||||
|
||||
return $lifespan_in_seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nonce validation message.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @return string The nonce validation message.
|
||||
*/
|
||||
private function nonce_validation_message() {
|
||||
return esc_html__( 'Your session has expired. Please refresh the page and try again.', 'gravityforms' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the validation summary properties to the form validation result.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param array $form The form being validated.
|
||||
* @param array $result The form validation result.
|
||||
*
|
||||
* @return mixed Returns the form validation result with the validation summary properties added.
|
||||
*/
|
||||
private function add_validation_summary( $form, $result ) {
|
||||
$summary = \GFFormDisplay::get_validation_errors_markup( $form, array(), rgar( $form, 'validationSummary' ) );
|
||||
$result['validation_summary'] = wp_kses( $summary, wp_kses_allowed_html( 'post' ) );
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/**
|
||||
* Service Provider for AJAX Service
|
||||
*
|
||||
* @package Gravity_Forms\Gravity_Forms\Ajax
|
||||
*/
|
||||
|
||||
namespace Gravity_Forms\Gravity_Forms\Ajax;
|
||||
|
||||
use Gravity_Forms\Gravity_Forms\Config\GF_Config_Service_Provider;
|
||||
use Gravity_Forms\Gravity_Forms\GF_Service_Container;
|
||||
use Gravity_Forms\Gravity_Forms\GF_Service_Provider;
|
||||
use Gravity_Forms\Gravity_Forms\Ajax\Config\GF_Ajax_Config;
|
||||
|
||||
/**
|
||||
* Class GF_Ajax_Service_Provider
|
||||
*
|
||||
* Service provider for the Ajax Service.
|
||||
*/
|
||||
class GF_Ajax_Service_Provider extends GF_Service_Provider {
|
||||
|
||||
const GF_AJAX_HANDLER = 'gf_ajax_handler';
|
||||
const GF_AJAX_CONFIG = 'gf_ajax_config';
|
||||
|
||||
/**
|
||||
* Includes all related files and adds all containers.
|
||||
*
|
||||
* @param GF_Service_Container $container Container singleton object.
|
||||
*/
|
||||
public function register( GF_Service_Container $container ) {
|
||||
|
||||
require_once plugin_dir_path( __FILE__ ) . 'class-gf-ajax-handler.php';
|
||||
require_once plugin_dir_path( __FILE__ ) . 'config/class-gf-ajax-config.php';
|
||||
|
||||
// Registering handler
|
||||
$container->add(
|
||||
self::GF_AJAX_HANDLER,
|
||||
function () {
|
||||
return new GF_Ajax_Handler();
|
||||
}
|
||||
);
|
||||
|
||||
// Registering config
|
||||
$container->add(
|
||||
self::GF_AJAX_CONFIG,
|
||||
function () use ( $container ) {
|
||||
return new GF_Ajax_Config( $container->get( GF_Config_Service_Provider::DATA_PARSER ) );
|
||||
}
|
||||
);
|
||||
$container->get( GF_Config_Service_Provider::CONFIG_COLLECTION )->add_config( $container->get( self::GF_AJAX_CONFIG ) );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes service.
|
||||
*
|
||||
* @param GF_Service_Container $container Service Container.
|
||||
*/
|
||||
public function init( GF_Service_Container $container ) {
|
||||
parent::init( $container );
|
||||
|
||||
$ajax_handler = $container->get( self::GF_AJAX_HANDLER );
|
||||
|
||||
// Register nonce lifespan hook.
|
||||
add_filter( 'nonce_life', array( $ajax_handler, 'nonce_life' ), 10, 2 );
|
||||
|
||||
// Register AJAX validation.
|
||||
add_action( 'wp_ajax_gform_validate_form', array( $ajax_handler, 'validate_form' ) );
|
||||
add_action( 'wp_ajax_nopriv_gform_validate_form', array( $ajax_handler, 'validate_form' ) );
|
||||
|
||||
// Register AJAX submission.
|
||||
add_action( 'wp_ajax_gform_submit_form', array( $ajax_handler, 'submit_form' ) );
|
||||
add_action( 'wp_ajax_nopriv_gform_submit_form', array( $ajax_handler, 'submit_form' ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Forms\Ajax\Config;
|
||||
|
||||
use Gravity_Forms\Gravity_Forms\Config\GF_Config;
|
||||
use GFForms;
|
||||
|
||||
/**
|
||||
* Config items for Ajax operations
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
class GF_Ajax_Config extends GF_Config {
|
||||
|
||||
protected $name = 'gform_theme_config';
|
||||
protected $script_to_localize = 'gform_gravityforms_theme';
|
||||
|
||||
/**
|
||||
* Config data.
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
public function data() {
|
||||
$preview_query_string = \GFCommon::is_preview() ? '?gf_ajax_page=preview' : '';
|
||||
return array(
|
||||
'common' => array(
|
||||
'form' => array(
|
||||
'ajax' => array(
|
||||
'ajaxurl' => admin_url( 'admin-ajax.php' ) . $preview_query_string,
|
||||
'ajax_submission_nonce' => wp_create_nonce( 'gform_ajax_submission' ),
|
||||
'i18n' => array(
|
||||
/* Translators: This is used to announce the current step of a multipage form, 1. first step number, 2. total steps number, example: Step 1 of 5 */
|
||||
'step_announcement' => esc_html__( 'Step %1$s of %2$s, %3$s', 'gravityforms' ),
|
||||
'unknown_error' => esc_html__( 'There was an unknown error processing your request. Please try again.', 'gravityforms' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -960,6 +960,11 @@ class GFAPI {
|
||||
}
|
||||
$transaction_type = ! empty( $entry['transaction_type'] ) ? intval( $entry['transaction_type'] ) : 'NULL';
|
||||
|
||||
if ( ! isset( $entry['source_id'] ) ) {
|
||||
$entry['source_id'] = null;
|
||||
}
|
||||
$source_id = ! empty( $entry['source_id'] ) ? absint( $entry['source_id'] ) : 'NULL';
|
||||
|
||||
$entry_table = GFFormsModel::get_entry_table_name();
|
||||
$sql = $wpdb->prepare(
|
||||
"
|
||||
@@ -983,7 +988,8 @@ class GFAPI {
|
||||
created_by = {$user_id},
|
||||
transaction_type = {$transaction_type},
|
||||
status = %s,
|
||||
payment_method = %s
|
||||
payment_method = %s,
|
||||
source_id = {$source_id}
|
||||
WHERE
|
||||
id = %d
|
||||
", $form_id, $is_starred, $is_read, $ip, $source_url, $user_agent, $currency, $status, $payment_method, $entry_id
|
||||
@@ -1236,6 +1242,7 @@ class GFAPI {
|
||||
$transaction_id = isset( $entry['transaction_id'] ) ? sprintf( "'%s'", esc_sql( $entry['transaction_id'] ) ) : 'NULL';
|
||||
$is_fulfilled = isset( $entry['is_fulfilled'] ) ? intval( $entry['is_fulfilled'] ) : 'NULL';
|
||||
$status = isset( $entry['status'] ) ? $entry['status'] : 'active';
|
||||
$source_id = isset( $entry['source_id'] ) ? absint( $entry['source_id'] ) : 'NULL';
|
||||
|
||||
global $current_user;
|
||||
$user_id = isset( $entry['created_by'] ) ? absint( $entry['created_by'] ) : '';
|
||||
@@ -1250,9 +1257,9 @@ class GFAPI {
|
||||
$wpdb->prepare(
|
||||
"
|
||||
INSERT INTO $entry_table
|
||||
(form_id, post_id, date_created, date_updated, is_starred, is_read, ip, source_url, user_agent, currency, payment_status, payment_date, payment_amount, transaction_id, is_fulfilled, created_by, transaction_type, status, payment_method)
|
||||
(form_id, post_id, date_created, date_updated, is_starred, is_read, ip, source_url, user_agent, currency, payment_status, payment_date, payment_amount, transaction_id, is_fulfilled, created_by, transaction_type, status, payment_method, source_id)
|
||||
VALUES
|
||||
(%d, {$post_id}, {$date_created}, {$date_updated}, %d, %d, %s, %s, %s, %s, {$payment_status}, {$payment_date}, {$payment_amount}, {$transaction_id}, {$is_fulfilled}, {$user_id}, {$transaction_type}, %s, %s)
|
||||
(%d, {$post_id}, {$date_created}, {$date_updated}, %d, %d, %s, %s, %s, %s, {$payment_status}, {$payment_date}, {$payment_amount}, {$transaction_id}, {$is_fulfilled}, {$user_id}, {$transaction_type}, %s, %s, {$source_id})
|
||||
", $form_id, $is_starred, $is_read, $ip, $source_url, $user_agent, $currency, $status, $payment_method
|
||||
)
|
||||
);
|
||||
@@ -1700,8 +1707,9 @@ class GFAPI {
|
||||
$result['validation_messages'] = self::get_field_validation_errors( $submission_details['form'] );
|
||||
}
|
||||
|
||||
$result['page_number'] = $submission_details['page_number'];
|
||||
$result['source_page_number'] = $submission_details['source_page_number'];
|
||||
$result['form'] = $submission_details['form'];
|
||||
$result['page_number'] = $submission_details['page_number'];
|
||||
$result['source_page_number'] = $submission_details['source_page_number'];
|
||||
|
||||
if ( $submission_details['is_valid'] ) {
|
||||
$confirmation_message = $submission_details['confirmation_message'];
|
||||
@@ -1720,6 +1728,7 @@ class GFAPI {
|
||||
}
|
||||
|
||||
$result['entry_id'] = rgars( $submission_details, 'lead/id' );
|
||||
$result['is_spam'] = rgars( $submission_details, 'is_spam' );
|
||||
}
|
||||
|
||||
if ( isset( $submission_details['resume_token'] ) ) {
|
||||
@@ -1777,6 +1786,7 @@ class GFAPI {
|
||||
'validation_messages' => array(),
|
||||
'page_number' => $is_valid ? $target_page : $failed_validation_page,
|
||||
'source_page_number' => $source_page,
|
||||
'form' => $form,
|
||||
);
|
||||
|
||||
if ( $is_valid ) {
|
||||
@@ -1964,6 +1974,7 @@ class GFAPI {
|
||||
* @since 1.8
|
||||
* @since 2.4.24 Updated $is_active to support using null to return both active and inactive feeds.
|
||||
* @since 2.6.1 Updated $form_ids to support an array of IDs.
|
||||
* @since 2.7.17 Added support for decrypting settings fields.
|
||||
*
|
||||
* @param mixed $feed_ids The ID of the Feed or an array of Feed IDs.
|
||||
* @param null|int|int[] $form_ids The ID of the Form to which the Feeds belong or array of Form IDs.
|
||||
@@ -2013,18 +2024,78 @@ class GFAPI {
|
||||
$sql .= ' WHERE ' . join( ' AND ', $where_arr );
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||
$results = $wpdb->get_results( $sql, ARRAY_A );
|
||||
if ( empty( $results ) ) {
|
||||
return new WP_Error( 'not_found', __( 'Feed not found', 'gravityforms' ) );
|
||||
}
|
||||
|
||||
foreach ( $results as &$result ) {
|
||||
$result['meta'] = json_decode( $result['meta'], true );
|
||||
$result['meta'] = self::get_encryptor()->decrypt_feed_meta( json_decode( $result['meta'], true ) );
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts feed meta fields based on feed settings fields configuratino and returns the resulting feed meta array.
|
||||
*
|
||||
* @since 2.7.17
|
||||
*
|
||||
* @param array $feed_meta The feed meta array to encrypt.
|
||||
* @param string $addon_slug The slug of the add-on to which the feed belongs.
|
||||
*
|
||||
* @return array Returns the feed meta arra with the fields that should be encrypted.
|
||||
*/
|
||||
public static function encrypt_feed_meta( $feed_meta, $addon_slug ) {
|
||||
|
||||
require_once( GFCommon::get_base_path() . '/includes/addon/class-gf-addon.php' );
|
||||
$addon = GFAddon::get_addon_by_slug( $addon_slug );
|
||||
if ( ! is_a( $addon, 'GFAddon' ) ) {
|
||||
return $feed_meta;
|
||||
}
|
||||
|
||||
return self::get_encryptor()->encrypt_feed_meta( $feed_meta, $addon->get_fields_to_encrypt() );
|
||||
}
|
||||
|
||||
/**
|
||||
* The encryption service object.
|
||||
*
|
||||
* @since 2.7.17
|
||||
*
|
||||
* @var \Gravity_Forms\Gravity_Forms\Settings\GF_Settings_Encryption The encryption service object.
|
||||
*/
|
||||
private static $_encryptor;
|
||||
|
||||
/**
|
||||
* Gets the encryption service object.
|
||||
*
|
||||
* @since 2.7.17
|
||||
*
|
||||
* @return \Gravity_Forms\Gravity_Forms\Settings\GF_Settings_Encryption An instance of the encryption service object.
|
||||
*/
|
||||
public static function get_encryptor() {
|
||||
if ( ! self::$_encryptor ) {
|
||||
require_once( GFCommon::get_base_path() . '/includes/settings/class-gf-settings-service-provider.php' );
|
||||
self::$_encryptor = GFForms::get_service_container()->get( \Gravity_Forms\Gravity_Forms\Settings\GF_Settings_Service_Provider::SETTINGS_ENCRYPTION );
|
||||
}
|
||||
|
||||
return self::$_encryptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the encryption service object to be used by GFAPI
|
||||
*
|
||||
* @since 2.7.17
|
||||
*
|
||||
* @param Gravity_Forms\Gravity_Forms\Settings\GF_Settings_Encryption $encryptor The encryption service object to be used.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function set_encryptor( $encryptor ) {
|
||||
self::$_encryptor = $encryptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specific feed.
|
||||
*
|
||||
@@ -2084,6 +2155,9 @@ class GFAPI {
|
||||
/**
|
||||
* Updates a feed.
|
||||
*
|
||||
* @since Unknown
|
||||
* @since 2.7.17 Added support for encrypting settings fields.
|
||||
*
|
||||
* @param int $feed_id The ID of the feed being updated.
|
||||
* @param array $feed_meta The feed meta to replace the existing feed meta.
|
||||
* @param null $form_id The ID of the form that the feed is associated with
|
||||
@@ -2103,6 +2177,8 @@ class GFAPI {
|
||||
return $lookup_result;
|
||||
}
|
||||
|
||||
$feed_meta = self::encrypt_feed_meta( $feed_meta, $lookup_result[0]['addon_slug'] );
|
||||
|
||||
$feed_meta_json = json_encode( $feed_meta );
|
||||
$table = $wpdb->prefix . 'gf_addon_feed';
|
||||
if ( empty( $form_id ) ) {
|
||||
@@ -2124,6 +2200,8 @@ class GFAPI {
|
||||
* Adds a feed with the given Feed object.
|
||||
*
|
||||
* @since 1.8
|
||||
* @since 2.7.17 Added support for encrypting settings fields.
|
||||
*
|
||||
* @access public
|
||||
* @global $wpdb
|
||||
*
|
||||
@@ -2150,6 +2228,8 @@ class GFAPI {
|
||||
return new WP_Error( 'not_found', __( 'Form not found', 'gravityforms' ) );
|
||||
}
|
||||
|
||||
$feed_meta = self::encrypt_feed_meta( $feed_meta, $addon_slug );
|
||||
|
||||
$feed_meta_json = json_encode( $feed_meta );
|
||||
$sql = $wpdb->prepare( "INSERT INTO {$table} (form_id, meta, addon_slug) VALUES (%d, %s, %s)", $form_id, $feed_meta_json, $addon_slug );
|
||||
|
||||
|
||||
@@ -44,4 +44,3 @@ class GF_Admin_Style_Dependencies extends GF_Dependencies {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -214,7 +214,7 @@ class GF_Block_Form extends GF_Block {
|
||||
}
|
||||
|
||||
// Get form output string.
|
||||
$form_string = gravity_form( $form_id, $title, $description, false, $field_values, $ajax, $tabindex, false );
|
||||
$form_string = gravity_form( $form_id, $title, $description, false, $field_values, $ajax, $tabindex, false, rgar( $attributes, 'theme' ), json_encode( $attributes ) );
|
||||
|
||||
// Get output buffer contents.
|
||||
$buffer_contents = ob_get_contents();
|
||||
@@ -236,7 +236,7 @@ class GF_Block_Form extends GF_Block {
|
||||
$field_values = '';
|
||||
}
|
||||
|
||||
return gravity_form( $form_id, $title, $description, false, $field_values, $ajax, $tabindex, false );
|
||||
return gravity_form( $form_id, $title, $description, false, $field_values, $ajax, $tabindex, false, rgar( $attributes, 'theme' ), json_encode( $attributes ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -132,6 +132,21 @@ class GF_Blocks_Service_Provider extends GF_Service_Provider {
|
||||
// buttonPrimaryBackgroundColor
|
||||
'default' => rgar( $global_styles, 'inputPrimaryColor' ) ? $global_styles['inputPrimaryColor'] : '', // #204ce5
|
||||
),
|
||||
'inputImageChoiceAppearance' =>
|
||||
array(
|
||||
'type' => 'string',
|
||||
'default' => rgar( $global_styles, 'inputImageChoiceAppearance' ) ? $global_styles['inputImageChoiceAppearance'] : 'card',
|
||||
),
|
||||
'inputImageChoiceStyle' =>
|
||||
array(
|
||||
'type' => 'string',
|
||||
'default' => rgar( $global_styles, 'inputImageChoiceStyle' ) ? $global_styles['inputImageChoiceStyle'] : 'square',
|
||||
),
|
||||
'inputImageChoiceSize' =>
|
||||
array(
|
||||
'type' => 'string',
|
||||
'default' => rgar( $global_styles, 'inputImageChoiceSize' ) ? $global_styles['inputImageChoiceSize'] : 'md',
|
||||
),
|
||||
'labelFontSize' =>
|
||||
array(
|
||||
'type' => 'string',
|
||||
|
||||
@@ -56,6 +56,7 @@ class GF_Blocks_Config extends GF_Config {
|
||||
'title' => $form['title'],
|
||||
'hasConditionalLogic' => GFFormDisplay::has_conditional_logic( $form ),
|
||||
'isLegacyMarkup' => GFCommon::is_legacy_markup_enabled( $form ),
|
||||
'hasImageChoices' => GFFormDisplay::has_image_choices( $form ),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -645,6 +645,7 @@ class GF_Upgrade {
|
||||
created_by bigint unsigned,
|
||||
transaction_type tinyint,
|
||||
status varchar(20) not null default 'active',
|
||||
source_id bigint unsigned,
|
||||
PRIMARY KEY (id),
|
||||
KEY form_id (form_id),
|
||||
KEY form_id_status (form_id,status)
|
||||
|
||||
@@ -39,31 +39,57 @@ class GF_Config_Collection {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function handle( $localize = true ) {
|
||||
public function handle( $localize = true, $args = null ) {
|
||||
|
||||
$scripts = $this->get_configs_by_script();
|
||||
$data_to_localize = array();
|
||||
|
||||
foreach ( $scripts as $script => $items ) {
|
||||
$item_data = $this->localize_data_for_script( $script, $items, $localize );
|
||||
$item_data = $this->localize_data_for_script( $script, $items, $localize, $args );
|
||||
$data_to_localize = array_merge( $data_to_localize, $item_data );
|
||||
}
|
||||
|
||||
return $data_to_localize;
|
||||
}
|
||||
|
||||
public function handle_ajax() {
|
||||
|
||||
// Check nonce.
|
||||
$nonce_result = check_ajax_referer( 'gform_config_ajax', 'gform_ajax_nonce', false );
|
||||
|
||||
if ( ! $nonce_result ) {
|
||||
wp_send_json_error( esc_html__( 'Unable to verify nonce. Please refresh the page and try again.', 'gravityforms' ) );
|
||||
}
|
||||
|
||||
$args = json_decode( rgpost( 'args' ), true );
|
||||
$config_path = rgpost( 'config_path' );
|
||||
$configs = $this->get_configs_by_path( $config_path, $args );
|
||||
|
||||
if ( ! $configs ) {
|
||||
wp_send_json_error( sprintf( esc_html__( 'Unable to find config: %s', 'gravityforms' ), $config_path ) );
|
||||
}
|
||||
|
||||
$data = $this->get_merged_data_for_object( $configs, $args );
|
||||
wp_send_json_success( $data );
|
||||
}
|
||||
/**
|
||||
* Localize the data for the given script.
|
||||
*
|
||||
* @since 2.6
|
||||
*
|
||||
* @param string $script
|
||||
* @param GF_Config[] $items
|
||||
* @param string $script The script to localize.
|
||||
* @param array $items The associative array of configs to process for this script.
|
||||
* @param bool $localize Whether to actually localize the data, or simply return it.
|
||||
* @param array $args The arguments to pass to the config objects.
|
||||
*
|
||||
* @return array Returns the localized data.
|
||||
*/
|
||||
private function localize_data_for_script( $script, $items, $localize = true ) {
|
||||
private function localize_data_for_script( $script, $items, $localize = true, $args = null ) {
|
||||
$data = array();
|
||||
|
||||
foreach ( $items as $name => $configs ) {
|
||||
$localized_data = $this->get_merged_data_for_object( $configs );
|
||||
|
||||
$localized_data = $this->get_merged_data_for_object( $configs, $args );
|
||||
|
||||
/**
|
||||
* Allows users to filter the data localized for a given script/resource.
|
||||
@@ -96,7 +122,7 @@ class GF_Config_Collection {
|
||||
*
|
||||
* @param GF_Config[] $configs
|
||||
*/
|
||||
private function get_merged_data_for_object( $configs ) {
|
||||
private function get_merged_data_for_object( $configs, $args ) {
|
||||
// Squash warnings for PHP < 7.0 when running tests.
|
||||
@usort( $configs, array( $this, 'sort_by_priority' ) );
|
||||
|
||||
@@ -104,6 +130,8 @@ class GF_Config_Collection {
|
||||
|
||||
foreach ( $configs as $config ) {
|
||||
|
||||
$config->set_args( $args );
|
||||
|
||||
// Config is set to overwrite data - simply return its value without attempting to merge.
|
||||
if ( $config->should_overwrite() ) {
|
||||
$data = $config->get_data();
|
||||
@@ -147,6 +175,27 @@ class GF_Config_Collection {
|
||||
return $data_to_localize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of configs that match the specified config path.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param string $config_path The path of the config to be returned.
|
||||
* @param array $args The arguments to pass to the config objects.
|
||||
*
|
||||
* @return array Returns an array of configs that are associated with the specified config path.
|
||||
*/
|
||||
private function get_configs_by_path( $config_path, $args )
|
||||
{
|
||||
$configs = array();
|
||||
foreach ( $this->configs as $config ) {
|
||||
if ( $config->enable_ajax( $config_path, $args ) ) {
|
||||
$configs[] = $config;
|
||||
}
|
||||
}
|
||||
return $configs;
|
||||
}
|
||||
|
||||
/**
|
||||
* usort() callback to sort the configs by their $priority.
|
||||
*
|
||||
@@ -162,4 +211,4 @@ class GF_Config_Collection {
|
||||
|
||||
return $a->priority() < $b->priority() ? - 1 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,15 @@ class GF_Config_Service_Provider extends GF_Service_Provider {
|
||||
$this->register_configs_to_collection( $container );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the config has been localized.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private static $is_localized = false;
|
||||
|
||||
/**
|
||||
* Initiailize any actions or hooks.
|
||||
*
|
||||
@@ -100,16 +109,43 @@ class GF_Config_Service_Provider extends GF_Service_Provider {
|
||||
$self = $this;
|
||||
|
||||
add_action( 'wp_enqueue_scripts', function () use ( $container ) {
|
||||
$container->get( self::CONFIG_COLLECTION )->handle();
|
||||
// Only localize during wp_enqueue_scripts if none of the other more specific events have been fired.
|
||||
if ( ! self::$is_localized ) {
|
||||
$container->get( self::CONFIG_COLLECTION )->handle();
|
||||
}
|
||||
}, 9999 );
|
||||
|
||||
add_action( 'admin_enqueue_scripts', function () use ( $container ) {
|
||||
$container->get( self::CONFIG_COLLECTION )->handle();
|
||||
// Only localize during admin_enqueue_scripts if none of the other more specific events have been fired.
|
||||
if ( ! self::$is_localized ) {
|
||||
$container->get( self::CONFIG_COLLECTION )->handle();
|
||||
}
|
||||
}, 9999 );
|
||||
|
||||
add_action( 'gform_preview_init', function () use ( $container ) {
|
||||
$container->get( self::CONFIG_COLLECTION )->handle();
|
||||
}, 0 );
|
||||
add_action( 'gform_output_config', function ( $form_ids = null ) use ( $container ) {
|
||||
$container->get( self::CONFIG_COLLECTION )->handle( true, $form_ids );
|
||||
self::$is_localized = true;
|
||||
} );
|
||||
|
||||
add_action( 'gform_post_enqueue_scripts', function ( $found_forms, $found_blocks, $post ) use ( $container ) {
|
||||
$form_ids = array_column( $found_forms, 'formId' );
|
||||
$container->get( self::CONFIG_COLLECTION )->handle( true, array( 'form_ids' => $form_ids ) );
|
||||
self::$is_localized = true;
|
||||
}, 10, 3);
|
||||
|
||||
add_action( 'gform_preview_init', function ( $form_id ) use ( $container ) {
|
||||
$form_ids = array( $form_id );
|
||||
$container->get( self::CONFIG_COLLECTION )->handle( true, array( 'form_ids' => $form_ids ) );
|
||||
self::$is_localized = true;
|
||||
}, 10, 2);
|
||||
|
||||
add_action('wp_ajax_gform_get_config', function () use ( $container ) {
|
||||
$container->get( self::CONFIG_COLLECTION )->handle_ajax();
|
||||
});
|
||||
|
||||
add_action('wp_ajax_nopriv_gform_get_config', function () use ( $container ) {
|
||||
$container->get( self::CONFIG_COLLECTION )->handle_ajax();
|
||||
});
|
||||
|
||||
add_action( 'rest_api_init', function () use ( $container, $self ) {
|
||||
register_rest_route( 'gravityforms/v2', '/tests/mock-data', array(
|
||||
@@ -206,4 +242,4 @@ class GF_Config_Service_Provider extends GF_Service_Provider {
|
||||
|
||||
return array_merge( $data, $global );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,13 @@ abstract class GF_Config {
|
||||
*/
|
||||
protected $overwrite = false;
|
||||
|
||||
/**
|
||||
* An args array. Use in the data() method to retrieve data specific to the specified args. For example, form specific configs will have an array of form ids specified in args.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $args = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@@ -98,6 +105,26 @@ abstract class GF_Config {
|
||||
*/
|
||||
abstract protected function data();
|
||||
|
||||
/**
|
||||
* Override this method to add enable ajax loading for a specific config path.
|
||||
* To enable loading data() via ajax, check if $config_path is one of the paths that are provided by the config. If so, return true.
|
||||
*
|
||||
* Example:
|
||||
* public function enable_ajax( $config_path, $args ) {
|
||||
* return str_starts_with( $config_path, 'gform_theme_config/common/form/product_meta' );
|
||||
* }
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param string $config_path The full path to the config item when stored in the browser's window object, for example: "gform_theme_config/common/form/product_meta"
|
||||
* @param array $args The args used to load the config data. This will be empty for generic config items. For form specific items will be in the format: array( 'form_ids' => array(123,222) ).
|
||||
*
|
||||
* @return bool Return true to load the config data associated with the provided $config_path. Return false otherwise.
|
||||
*/
|
||||
public function enable_ajax( $config_path, $args ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the config should enqueue its data. If should_enqueue() is a method,
|
||||
* call it and return the result. If not, simply return the (boolean) value of the property.
|
||||
@@ -187,4 +214,68 @@ abstract class GF_Config {
|
||||
return $this->overwrite;
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* Sets the $form_ids arrays.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param array $args Args array to be set
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set_args( $args ) {
|
||||
$this->args = $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the config data against a hash to ensure it has not been tampered with.
|
||||
* This method is called via AJAX, initiated by the gform.config.isValid() JS method.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function validate_ajax() {
|
||||
|
||||
// Check nonce
|
||||
$nonce_result = check_ajax_referer( 'gform_config_ajax', 'gform_ajax_nonce', false );
|
||||
|
||||
if ( ! $nonce_result ) {
|
||||
wp_send_json_error( esc_html__( 'Unable to verify nonce. Please refresh the page and try again.', 'gravityforms' ) );
|
||||
}
|
||||
|
||||
$config = json_decode( rgpost( 'config' ), true );
|
||||
$hash = rgar( $config, 'hash' );
|
||||
if ( ! $hash ) {
|
||||
wp_send_json_error( esc_html__( 'Invalid config.', 'gravityforms' ) );
|
||||
}
|
||||
|
||||
// Remove hash from config before validating.
|
||||
unset( $config['hash'] );
|
||||
|
||||
// Compare hash to config.
|
||||
if ( $hash !== self::hash( $config ) ) {
|
||||
wp_send_json_error( esc_html__( 'Config validation failed. Hash does not match', 'gravityforms' ) );
|
||||
}
|
||||
|
||||
// Send success response.
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashes the config data.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param array $config
|
||||
*
|
||||
* @return string Returns the hash of the config data.
|
||||
*/
|
||||
public static function hash( $config ) {
|
||||
return wp_hash( json_encode( $config ) );
|
||||
}
|
||||
}
|
||||
|
||||
// AJAX hash validation for config data.
|
||||
add_action('wp_ajax_gform_validate_config', array( 'Gravity_Forms\Gravity_Forms\Config\GF_Config', 'validate_ajax' ) );
|
||||
add_action('wp_ajax_nopriv_gform_validate_config', array( 'Gravity_Forms\Gravity_Forms\Config\GF_Config', 'validate_ajax' ) );
|
||||
|
||||
@@ -19,6 +19,7 @@ class GF_Config_Global {
|
||||
return array(
|
||||
'hmr_dev' => defined( 'GF_ENABLE_HMR' ) && GF_ENABLE_HMR,
|
||||
'public_path' => trailingslashit( \GFCommon::get_base_url() ) . 'assets/js/dist/',
|
||||
'config_nonce' => wp_create_nonce( 'gform_config_ajax' ),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -49,8 +49,8 @@ class GF_Embed_Config_I18N extends GF_Config {
|
||||
'create_button_label' => esc_html__( 'Create', 'gravityforms' ),
|
||||
'dialog_title' => esc_html__( 'Unsaved Changes', 'gravityforms' ),
|
||||
'dialog_content' => esc_html__( 'Oops! You have unsaved changes in the form, before you can continue with embedding it please save your changes.', 'gravityforms' ),
|
||||
'dialog_confirm_text' => esc_html__( 'Save Changes', 'gravityforms' ),
|
||||
'dialog_confirm_saving' => esc_html__( 'Saving', 'gravityforms' ),
|
||||
'dialog_confirm_text' => esc_html__( 'Save Changes', 'gravityforms' ),
|
||||
'dialog_confirm_saving' => esc_html__( 'Saving', 'gravityforms' ),
|
||||
'dialog_cancel_text' => esc_html__( 'Cancel', 'gravityforms' ),
|
||||
'dialog_close_title' => esc_html__( 'Close this dialog and return to form editor.', 'gravityforms' ),
|
||||
'shortcode_title' => esc_html__( 'Not Using the Block Editor?', 'gravityforms' ),
|
||||
|
||||
@@ -79,7 +79,7 @@ class GF_Field_Calculation extends GF_Field {
|
||||
|
||||
if ( $is_entry_detail || $is_form_editor ) {
|
||||
$style = $this->disableQuantity ? "style='display:none;'" : '';
|
||||
$quantity_field = " <span class='ginput_quantity_label gform-field-label gform-field-label--type-sub-large' {$style}>{$product_quantity_sub_label}</span> <input type='number' name='input_{$id}.3' value='{$quantity}' id='ginput_quantity_{$form_id}_{$this->id}' class='ginput_quantity' size='10' min='0' {$disabled_text} />";
|
||||
$quantity_field = " <span class='ginput_quantity_label gform-field-label' {$style}>{$product_quantity_sub_label}</span> <input type='number' name='input_{$id}.3' value='{$quantity}' id='ginput_quantity_{$form_id}_{$this->id}' class='ginput_quantity' size='10' min='0' {$disabled_text} />";
|
||||
} elseif ( ! $this->disableQuantity ) {
|
||||
$tabindex = $this->get_tabindex();
|
||||
$describedby_extra_id = array();
|
||||
@@ -107,7 +107,7 @@ class GF_Field_Calculation extends GF_Field {
|
||||
<span class='gform-field-label gform-field-label--type-sub-large ginput_product_price_label'>" . gf_apply_filters( array( 'gform_product_price', $form_id, $this->id ), esc_html__( 'Price', 'gravityforms' ), $form_id ) . ":</span>
|
||||
<span class='gform-field-label gform-field-label--type-sub-large ginput_product_price' id='{$field_id}'>" . esc_html( GFCommon::to_money( $price, $currency ) ) . "</span>
|
||||
$wrapper_close
|
||||
<input type='hidden' name='input_{$id}.2' id='ginput_base_price_{$form_id}_{$this->id}' class='gform_hidden' value='" . esc_attr( $price ) . "'/>
|
||||
<input type='hidden' name='input_{$id}.2' id='ginput_base_price_{$form_id}_{$this->id}' class='gform_hidden ginput_calculated_price' value='" . esc_attr( $price ) . "'/>
|
||||
{$quantity_field}
|
||||
</div>";
|
||||
}
|
||||
|
||||
@@ -41,6 +41,9 @@ class GF_Field_CAPTCHA extends GF_Field {
|
||||
* @param $data
|
||||
*/
|
||||
public function __construct( $data = array() ) {
|
||||
add_filter( 'gform_ajax_submission_result', array( 'GF_Field_CAPTCHA', 'set_recaptcha_response' ) );
|
||||
add_filter( 'gform_ajax_validation_result', array( 'GF_Field_CAPTCHA', 'set_recaptcha_response' ) );
|
||||
|
||||
parent::__construct( $data );
|
||||
|
||||
if ( ! has_filter( 'gform_pre_render', array( __CLASS__, 'maybe_remove_recaptcha_v2' ) ) ) {
|
||||
@@ -48,7 +51,33 @@ class GF_Field_CAPTCHA extends GF_Field {
|
||||
}
|
||||
}
|
||||
|
||||
public function get_form_editor_field_title() {
|
||||
/**
|
||||
* Add recaptcha response to the AJAX request result.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param array $result The result of the AJAX validation and submission request.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function set_recaptcha_response( $result ) {
|
||||
$form = $result['form'];
|
||||
|
||||
// Adding recaptcha response to the result.
|
||||
$recaptcha_field = \GFFormsModel::get_fields_by_type( $form, array( 'captcha' ) );
|
||||
if ( empty( $recaptcha_field ) ) {
|
||||
return $result;
|
||||
}
|
||||
$recaptcha_field = $recaptcha_field[0];
|
||||
$recaptcha_response = $recaptcha_field->get_encoded_recaptcha_response( $form, $recaptcha_field->get_posted_recaptcha_response() );
|
||||
if ( $recaptcha_field->verify_decoded_response( $form, $recaptcha_response ) ) {
|
||||
$result['recaptcha_response'] = $recaptcha_response;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function get_form_editor_field_title() {
|
||||
return esc_attr__( 'CAPTCHA', 'gravityforms' );
|
||||
}
|
||||
|
||||
@@ -111,18 +140,29 @@ class GF_Field_CAPTCHA extends GF_Field {
|
||||
if ( ( ! empty( $this->get_site_key() ) && ! empty( $this->get_secret_key() ) ) ) {
|
||||
if ( is_plugin_active( 'gravityformsconversationalforms/conversationalforms.php' ) ) {
|
||||
return array(
|
||||
'type' => 'notice',
|
||||
'content' => esc_html__( 'The reCAPTCHA v2 field is not supported in Conversational Forms and will be removed, but will continue to work as expected in other contexts.', 'gravityforms' )
|
||||
'type' => 'notice',
|
||||
'content' => sprintf(
|
||||
'<div class="gform-typography--weight-regular">%s</div>',
|
||||
__( 'The reCAPTCHA v2 field is not supported in Conversational Forms and will be removed, but will continue to work as expected in other contexts.', 'gravityforms' )
|
||||
),
|
||||
'icon_helper_text' => __( 'This field is not supported in Conversational Forms', 'gravityforms' ),
|
||||
);
|
||||
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
// If the reCAPTCHA keys are not configured, we need to display a warning.
|
||||
// Translators: 1. Opening <a> tag with link to the Forms > Settings > reCAPTCHA page. 2. closing <a> tag.
|
||||
return sprintf( __( 'To use reCAPTCHA v2 you must configure the site and secret keys on the %1$sreCAPTCHA Settings%2$s page.', 'gravityforms' ), "<a href='?page=gf_settings&subview=recaptcha' target='_blank'>", '</a>' );
|
||||
return array(
|
||||
'type' => 'notice',
|
||||
'content' => sprintf(
|
||||
'%s<div class="gform-spacing gform-spacing--top-1">%s</div>',
|
||||
__( 'Configuration Required', 'gravityforms' ),
|
||||
// Translators: 1. Opening <a> tag with link to the Forms > Settings > reCAPTCHA page. 2. closing <a> tag.
|
||||
sprintf( __( 'To use the reCAPTCHA field, please configure your %1$sreCAPTCHA settings%2$s.', 'gravityforms' ), '<a href="?page=gf_settings&subview=recaptcha" target="_blank">', '</a>' )
|
||||
),
|
||||
'icon_helper_text' => __( 'This field requires additional configuration', 'gravityforms' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -242,6 +282,7 @@ class GF_Field_CAPTCHA extends GF_Field {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$response = $this->get_posted_recaptcha_response();
|
||||
|
||||
if ( ! ( $this->verify_decoded_response( $form, $response ) || $this->verify_recaptcha_response( $response ) ) ) {
|
||||
@@ -265,7 +306,7 @@ class GF_Field_CAPTCHA extends GF_Field {
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function verify_decoded_response( $form, $response ) {
|
||||
public function verify_decoded_response( $form, $response ) {
|
||||
$decoded_response = $this->get_decoded_recaptcha_response( $response );
|
||||
|
||||
// No decoded object.
|
||||
@@ -273,11 +314,6 @@ class GF_Field_CAPTCHA extends GF_Field {
|
||||
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 )
|
||||
@@ -306,7 +342,7 @@ class GF_Field_CAPTCHA extends GF_Field {
|
||||
*/
|
||||
public function get_site_key() {
|
||||
if ( ! $this->site_key ) {
|
||||
$this->site_key = get_option( 'rg_gforms_captcha_public_key', '' );
|
||||
$this->site_key = get_option( 'rg_gforms_captcha_public_key', '' );
|
||||
}
|
||||
|
||||
return $this->site_key;
|
||||
@@ -341,7 +377,7 @@ class GF_Field_CAPTCHA extends GF_Field {
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_posted_recaptcha_response() {
|
||||
public function get_posted_recaptcha_response() {
|
||||
return sanitize_text_field( rgpost( 'g-recaptcha-response' ) );
|
||||
}
|
||||
|
||||
@@ -425,11 +461,28 @@ class GF_Field_CAPTCHA extends GF_Field {
|
||||
$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='ginput_container'><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 %sreCAPTCHA Settings%s.', 'gravityforms' ), "<a href='?page=gf_settings&subview=recaptcha' target='_blank'>", '</a>' ) . '</div></div>';
|
||||
}
|
||||
return '<div class="ginput_container ginput_container_addon_message ginput_container_addon_message_captcha">
|
||||
<div class="gform-alert gform-alert--info gform-alert--theme-cosmos gform-spacing gform-spacing--bottom-0 gform-theme__disable">
|
||||
<span
|
||||
class="gform-icon gform-icon--information-simple gform-icon--preset-active gform-icon-preset--status-info gform-alert__icon"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
<div class="gform-alert__message-wrap">
|
||||
<div class="gform-alert__message">
|
||||
'. __( 'Configuration Required', 'gravityforms' ) .'
|
||||
<div class="gform-spacing gform-spacing--top-1">'. sprintf(
|
||||
'%s %s%s%s.',
|
||||
__( 'To use the reCAPTCHA field, please configure your', 'gravityforms' ),
|
||||
'<a href="?page=gf_settings&subview=recaptcha" target="_blank">',
|
||||
__( 'reCAPTCHA settings', 'gravityforms' ),
|
||||
'</a>'
|
||||
) .'</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>';
|
||||
}
|
||||
|
||||
$type_suffix = $type == 'invisible' ? 'invisible_' : '';
|
||||
$alt = esc_attr__( 'An example of reCAPTCHA', 'gravityforms' );
|
||||
@@ -491,7 +544,7 @@ class GF_Field_CAPTCHA extends GF_Field {
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_encoded_recaptcha_response( $form, $response ) {
|
||||
public function get_encoded_recaptcha_response( $form, $response ) {
|
||||
if ( ! $this->response ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
require_once( plugin_dir_path( __FILE__ ) . 'field-decorator-choice/class-gf-field-decorator-choice-checkbox-markup.php' );
|
||||
|
||||
class GF_Field_Checkbox extends GF_Field {
|
||||
|
||||
/**
|
||||
@@ -120,6 +122,12 @@ class GF_Field_Checkbox extends GF_Field {
|
||||
|
||||
}
|
||||
|
||||
public function get_default_properties() {
|
||||
return array(
|
||||
'selectAllText' => esc_html__( 'Select All', 'gravityforms' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the field inner markup.
|
||||
*
|
||||
@@ -135,6 +143,11 @@ class GF_Field_Checkbox extends GF_Field {
|
||||
*/
|
||||
public function get_field_input( $form, $value = '', $entry = null ) {
|
||||
|
||||
if ( $this->type == 'image_choice' ) {
|
||||
$this->image_markup = new GF_Field_Decorator_Choice_Checkbox_Markup( $this );
|
||||
return $this->image_markup->get_field_input( $form, $value, $entry );
|
||||
}
|
||||
|
||||
$form_id = absint( $form['id'] );
|
||||
|
||||
if ( GFCommon::is_legacy_markup_enabled( $form ) ) {
|
||||
@@ -151,14 +164,35 @@ class GF_Field_Checkbox extends GF_Field {
|
||||
// Get checkbox choices markup.
|
||||
$choices_markup = $this->get_checkbox_choices( $value, $disabled_text, $form_id );
|
||||
|
||||
if ( ! $this->enableSelectAll ) {
|
||||
// Get button markup.
|
||||
$button_markup = $this->get_button_markup( $value, $entry );
|
||||
|
||||
$select_all_enabled_class = $this->enableSelectAll ? 'gfield_choice--select_all_enabled' : '';
|
||||
|
||||
$limit_message = $this->get_limit_message();
|
||||
|
||||
if ( 'multi_choice' == $this->type || ! $this->enableSelectAll ) {
|
||||
return sprintf(
|
||||
"<div class='ginput_container ginput_container_checkbox'><div class='gfield_checkbox' id='%s'>%s</div></div>",
|
||||
"<div class='ginput_container ginput_container_checkbox'>%s<div class='gfield_checkbox %s' id='%s'>%s</div></div>",
|
||||
$limit_message,
|
||||
$select_all_enabled_class,
|
||||
esc_attr( $field_id ),
|
||||
$choices_markup
|
||||
);
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
"<div class='ginput_container ginput_container_checkbox'>%s<div class='gfield_checkbox %s' id='%s'>%s%s</div></div>",
|
||||
$limit_message,
|
||||
$select_all_enabled_class,
|
||||
esc_attr( $field_id ),
|
||||
$choices_markup,
|
||||
$button_markup
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public function get_button_markup( $value, $entry ) {
|
||||
/**
|
||||
* Modify the "Select All" checkbox label.
|
||||
*
|
||||
@@ -192,16 +226,139 @@ class GF_Field_Checkbox extends GF_Field {
|
||||
$deselect_label,
|
||||
$all_selected ? 1 : 0,
|
||||
$all_selected ? $deselect_label : $select_label,
|
||||
$is_form_editor ? ' disabled="disabled"' : ''
|
||||
$this->is_form_editor() ? ' disabled="disabled"' : ''
|
||||
);
|
||||
|
||||
return sprintf(
|
||||
"<div class='ginput_container ginput_container_checkbox'><div class='gfield_checkbox' id='%s'>%s%s</div></div>",
|
||||
esc_attr( $field_id ),
|
||||
$choices_markup,
|
||||
$button_markup
|
||||
);
|
||||
return $button_markup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message that describes the choice limit.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_limit_message() {
|
||||
$text = $this->get_limit_message_text();
|
||||
if ( ! $text ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$form_id = $this->formId;
|
||||
$form = GFAPI::get_form( $form_id );
|
||||
|
||||
// If the validation message is the same as the limit message, and they both display above the field, don't display the limit message.
|
||||
if ( $this->failed_validation && $this->validation_message === $text && $this->is_validation_above( $form ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$id = $this->id;
|
||||
|
||||
return "<span class='gfield_choice_limit_message gfield_description' id='gfield_choice_limit_message_{$form_id}_{$id}'>{$text}</span>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text of the choice limit message, or return false if there is no limit.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @return false|string
|
||||
*/
|
||||
public function get_limit_message_text() {
|
||||
if ( $this->choiceLimit === 'exactly' && $this->choiceLimitNumber ) {
|
||||
$message = sprintf(
|
||||
esc_attr(
|
||||
_n(
|
||||
'Select exactly %s choice.',
|
||||
'Select exactly %s choices.',
|
||||
$this->choiceLimitNumber,
|
||||
'gravityforms'
|
||||
)
|
||||
),
|
||||
"<strong>$this->choiceLimitNumber</strong>"
|
||||
);
|
||||
|
||||
/**
|
||||
* Modify the message displayed when a checkbox is limited to an exact number of entries.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param string $message The message to filter.
|
||||
* @param int $number The number of choices that must be selected.
|
||||
* @param object $field The field currently being processed.
|
||||
*/
|
||||
return gf_apply_filters( array( 'gform_checkbox_limit_exact_message', $this->formId, $this->id ), $message, $this->choiceLimitNumber, $this );
|
||||
}
|
||||
if ( $this->choiceLimit === 'range' ) {
|
||||
$min = $this->choiceLimitMin;
|
||||
$max = $this->choiceLimitMax;
|
||||
if ( ! $min && $max ) {
|
||||
$message = sprintf(
|
||||
esc_attr(
|
||||
_n(
|
||||
'Select up to %s choice.',
|
||||
'Select up to %s choices.',
|
||||
$max,
|
||||
'gravityforms'
|
||||
)
|
||||
),
|
||||
"<strong>$max</strong>"
|
||||
);
|
||||
|
||||
/**
|
||||
* Modify the message displayed when a checkbox is limited to a maximum number of choices.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param string $message The message to filter.
|
||||
* @param int $max The maximum number of choices that must be selected.
|
||||
* @param object $field The field currently being processed.
|
||||
*/
|
||||
return gf_apply_filters( array( 'gform_checkbox_limit_max_message', $this->formId, $this->id ), $message, $max, $this );
|
||||
}
|
||||
if ( ! $max && $min ) {
|
||||
$message = sprintf(
|
||||
esc_attr(
|
||||
_n(
|
||||
'Select at least %s choice.',
|
||||
'Select at least %s choices.',
|
||||
$min,
|
||||
'gravityforms'
|
||||
)
|
||||
),
|
||||
"<strong>$min</strong>"
|
||||
);
|
||||
|
||||
/**
|
||||
* Modify the message displayed when a checkbox is limited to a minimum number of choices.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param string $message The message to filter.
|
||||
* @param int $min The minimum number of choices that must be selected.
|
||||
* @param object $field The field currently being processed.
|
||||
*/
|
||||
return gf_apply_filters( array( 'gform_checkbox_limit_min_message', $this->formId, $this->id ), $message, $min, $this );
|
||||
}
|
||||
if( $min && $max ) {
|
||||
$message = sprintf( esc_html__( 'Select between %s and %s choices.', 'gravityforms' ), "<strong>$min</strong>", "<strong>$max</strong>" );
|
||||
|
||||
/**
|
||||
* Modify the message displayed when a checkbox is limited to a maximum number of entries.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param string $message The message to filter.
|
||||
* @param int $min The minimum number of choices that must be selected.
|
||||
* @param int $max The maximum number of choices that must be selected.
|
||||
* @param object $field The field currently being processed.
|
||||
*/
|
||||
return gf_apply_filters( array( 'gform_checkbox_limit_range_message', $this->formId, $this->id ), $message, $min, $max, $this );
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -259,7 +416,11 @@ class GF_Field_Checkbox extends GF_Field {
|
||||
}
|
||||
|
||||
// Prepare input ID.
|
||||
$input_id = $this->id . '.' . $choice_number;
|
||||
if ( rgar( $choice, 'key' ) ) {
|
||||
$input_id = $this->get_input_id_from_choice_key( $choice['key'] );
|
||||
} else {
|
||||
$input_id = $this->id . '.' . $choice_number;
|
||||
}
|
||||
|
||||
if ( ( $this->is_form_editor() || ( ! isset( $_GET['gf_token'] ) && empty( $_POST ) ) ) && rgar( $choice, 'isSelected' ) ) {
|
||||
$checkboxes_selected++;
|
||||
@@ -273,7 +434,6 @@ class GF_Field_Checkbox extends GF_Field {
|
||||
|
||||
}
|
||||
|
||||
|
||||
return $checkboxes_selected;
|
||||
|
||||
}
|
||||
@@ -336,7 +496,17 @@ class GF_Field_Checkbox extends GF_Field {
|
||||
|
||||
$item = trim( $item );
|
||||
|
||||
if ( GFFormsModel::choice_value_match( $this, $this->choices[ $choice_index ], $item ) ) {
|
||||
if ( rgar( $input, 'key' ) ) {
|
||||
$choice_id = $this->get_choice_id_from_input_key( $input['key'] );
|
||||
if ( '' == $choice_id ) {
|
||||
continue;
|
||||
}
|
||||
$choice = $this->choices[ $choice_id ];
|
||||
} else {
|
||||
$choice = $this->choices[ $choice_index ];
|
||||
}
|
||||
|
||||
if ( GFFormsModel::choice_value_match( $this, $choice, $item ) ) {
|
||||
$value[ $input['id'] . '' ] = $item;
|
||||
break;
|
||||
}
|
||||
@@ -356,7 +526,27 @@ class GF_Field_Checkbox extends GF_Field {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function validate( $value, $form ) {
|
||||
if ( $this->choiceLimit == 'exactly' ) {
|
||||
$selected_choices_count = $this->get_selected_choices_count( $value );
|
||||
if ( 0 === $selected_choices_count ) {
|
||||
return;
|
||||
}
|
||||
if ( $selected_choices_count != $this->choiceLimitNumber ) {
|
||||
$this->failed_validation = true;
|
||||
$this->validation_message = $this->get_limit_message_text();
|
||||
}
|
||||
} elseif ( $this->choiceLimit == 'range' ) {
|
||||
$selected_choices_count = $this->get_selected_choices_count( $value );
|
||||
if ( 0 === $selected_choices_count ) {
|
||||
return;
|
||||
}
|
||||
if ( ( $this->choiceLimitMin && $selected_choices_count < $this->choiceLimitMin ) || ( $this->choiceLimitMax && $selected_choices_count > $this->choiceLimitMax ) ) {
|
||||
$this->failed_validation = true;
|
||||
$this->validation_message = $this->get_limit_message_text();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -403,7 +593,6 @@ class GF_Field_Checkbox extends GF_Field {
|
||||
if ( $this->type == 'post_category' ) {
|
||||
$value = GFCommon::prepare_post_category_value( $value, $this, 'entry_list' );
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$value = '';
|
||||
@@ -437,7 +626,6 @@ class GF_Field_Checkbox extends GF_Field {
|
||||
* @return string
|
||||
*/
|
||||
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
|
||||
|
||||
if ( is_array( $value ) ) {
|
||||
|
||||
$items = '';
|
||||
@@ -511,6 +699,7 @@ class GF_Field_Checkbox extends GF_Field {
|
||||
$use_value = in_array( 'value', $modifiers );
|
||||
$format_currency = in_array( 'currency', $modifiers );
|
||||
$use_price = $format_currency || in_array( 'price', $modifiers );
|
||||
$image_url = in_array( 'img_url', $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.
|
||||
@@ -524,38 +713,40 @@ class GF_Field_Checkbox extends GF_Field {
|
||||
|
||||
// Get the items available within the merge tags.
|
||||
foreach ( $items as $input_id => $item ) {
|
||||
switch (true) {
|
||||
// If the 'value' modifier was passed.
|
||||
case $use_value:
|
||||
list( $val, $price ) = rgexplode( '|', $item, 2 );
|
||||
break;
|
||||
|
||||
// If the 'value' modifier was passed.
|
||||
if ( $use_value ) {
|
||||
// If the 'price' or 'currency' modifiers were passed.
|
||||
case $use_price:
|
||||
list( $name, $val ) = rgexplode( '|', $item, 2 );
|
||||
if ( $format_currency ) {
|
||||
$val = GFCommon::to_money( $val, rgar( $entry, 'currency' ) );
|
||||
}
|
||||
break;
|
||||
|
||||
list( $val, $price ) = rgexplode( '|', $item, 2 );
|
||||
// If the 'image_url' modifier was passed.
|
||||
case $image_url:
|
||||
$image_choice = new GF_Field_Image_Choice( $this );
|
||||
$val = $image_choice->get_merge_tag_img_url( $raw_value, $input_id, $entry, $form, $this );
|
||||
break;
|
||||
|
||||
// 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 );
|
||||
// If this is a post category checkbox.
|
||||
case $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;
|
||||
break;
|
||||
|
||||
// If no modifiers were passed.
|
||||
default:
|
||||
$val = GFFormsModel::is_field_hidden( $form, $this, array(), $entry ) ? '' : RGFormsModel::get_choice_text( $this, $raw_value, $input_id );
|
||||
break;
|
||||
}
|
||||
|
||||
$ary[] = GFCommon::format_variable_value( $val, $url_encode, $esc_html, $format );
|
||||
|
||||
}
|
||||
|
||||
return GFCommon::implode_non_blank( ', ', $ary );
|
||||
@@ -606,6 +797,29 @@ class GF_Field_Checkbox extends GF_Field {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the entry inputs in the order they are configured in the form editor.
|
||||
*
|
||||
* @since 2.9
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function get_entry_inputs() {
|
||||
if ( $this->has_persistent_choices() && is_array( $this->inputs ) ) {
|
||||
$inputs_by_key = array_column( $this->inputs, null, 'key' );
|
||||
$sorted_inputs = array();
|
||||
|
||||
foreach ( $this->choices as $choice ) {
|
||||
if ( isset( $inputs_by_key[ $choice['key'] ] ) ) {
|
||||
$sorted_inputs[] = $inputs_by_key[ $choice['key'] ];
|
||||
}
|
||||
}
|
||||
return $sorted_inputs;
|
||||
} else {
|
||||
return $this->inputs;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the entry value before it is used in entry exports and by framework add-ons using GFAddOn::get_field_value().
|
||||
*
|
||||
@@ -690,11 +904,23 @@ class GF_Field_Checkbox extends GF_Field {
|
||||
|
||||
$choice_number = 1;
|
||||
$count = 1;
|
||||
|
||||
/**
|
||||
* A filter that allows for the setting of the maximum number of choices shown in
|
||||
* the form editor for choice based fields (radio, checkbox, image, and multiple choice).
|
||||
*
|
||||
* @since 2.9
|
||||
*
|
||||
* @param int $max_choices_visible_count The default number of choices visible is 5.
|
||||
* @param object $field The current field object.
|
||||
*/
|
||||
$max_choices_count = gf_apply_filters( array( 'gform_field_choices_max_count_visible', $form_id ), 5, $this );
|
||||
|
||||
$legacy_markup = GFCommon::is_legacy_markup_enabled( $form_id );
|
||||
|
||||
$tag = $legacy_markup ? 'li' : 'div';
|
||||
|
||||
// Add Select All choice.
|
||||
// Add Select All choice for legacy markup.
|
||||
if ( $this->enableSelectAll && $legacy_markup ) {
|
||||
|
||||
/**
|
||||
@@ -754,11 +980,22 @@ class GF_Field_Checkbox extends GF_Field {
|
||||
|
||||
}
|
||||
|
||||
$need_aria_describedby = true;
|
||||
|
||||
// Add select all choice for the Multiple Choice field.
|
||||
if ( $this->type == 'multi_choice' && $this->enableSelectAll ) {
|
||||
$this->choice_field = new GF_Field_Multiple_Choice( $this );
|
||||
$selected_choices_count = $this->get_selected_choices_count( $value );
|
||||
$tabindex = $this->get_tabindex();
|
||||
$need_aria_describedby = false; // We're going to add the aria-describedby attribute to the "Select All" choice, so we don't need it later on the first choice.
|
||||
|
||||
$choices .= $this->choice_field->get_choice_field_select_all_markup( $value, $tabindex, $selected_choices_count );
|
||||
}
|
||||
|
||||
// Loop through field choices.
|
||||
foreach ( $this->choices as $choice ) {
|
||||
|
||||
// Get aria-describedby if this is the first choice
|
||||
$aria_describedby = $choice_number === 1 ? $this->get_aria_describedby() : '';
|
||||
$aria_describedby = ( $choice_number === 1 && $need_aria_describedby ) ? $this->get_choice_aria_describedby( $form_id ) : '';
|
||||
|
||||
// Hack to skip numbers ending in 0, so that 5.1 doesn't conflict with 5.10.
|
||||
if ( $choice_number % 10 == 0 ) {
|
||||
@@ -766,7 +1003,13 @@ class GF_Field_Checkbox extends GF_Field {
|
||||
}
|
||||
|
||||
// Prepare input ID.
|
||||
$input_id = $this->id . '.' . $choice_number;
|
||||
$input_id = '';
|
||||
if ( $this->has_persistent_choices() ) {
|
||||
$input_id = $this->get_input_id_from_choice_key( $choice['key'] );
|
||||
} else {
|
||||
// Regular checkboxes field generates input IDs on the fly.
|
||||
$input_id = $this->id . '.' . $choice_number;
|
||||
}
|
||||
|
||||
if ( $is_entry_detail || $is_form_editor || $form_id == 0 ) {
|
||||
$id = $this->id . '_' . $choice_number ++;
|
||||
@@ -774,16 +1017,7 @@ class GF_Field_Checkbox extends GF_Field {
|
||||
$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 ) && ! empty( $_POST[ 'is_submit_' . $form_id ] ) ) {
|
||||
$checked = "checked='checked'";
|
||||
} else {
|
||||
$checked = '';
|
||||
}
|
||||
|
||||
$checked = $this->get_checked_attribute( $choice, $value, $input_id, $form_id );
|
||||
$tabindex = $this->get_tabindex();
|
||||
$choice_value = $choice['value'];
|
||||
|
||||
@@ -812,7 +1046,7 @@ class GF_Field_Checkbox extends GF_Field {
|
||||
|
||||
$is_admin = $is_entry_detail || $is_form_editor;
|
||||
|
||||
if ( $is_admin && rgget('view') != 'entry' && $count >= 5 ) {
|
||||
if ( $is_admin && rgget('view') != 'entry' && $count >= $max_choices_count ) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -823,7 +1057,7 @@ class GF_Field_Checkbox extends GF_Field {
|
||||
$total = sizeof( $this->choices );
|
||||
|
||||
if ( $count < $total ) {
|
||||
$choices .= "<{$tag} class='gchoice_total'>" . sprintf( esc_html__( '%d of %d items shown. Edit field to view all', 'gravityforms' ), $count, $total ) . "</{$tag}>";
|
||||
$choices .= "<{$tag} class='gchoice_total'><span>" . sprintf( esc_html__( '%d of %d items shown. Edit choices to view all.', 'gravityforms' ), $count, $total ) . "</span></{$tag}>";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -834,12 +1068,53 @@ class GF_Field_Checkbox extends GF_Field {
|
||||
* @since Unknown
|
||||
*
|
||||
* @param string $choices The string containing the choices to be filtered.
|
||||
* @param object $field Ahe field currently being processed.
|
||||
* @param object $field The field currently being processed.
|
||||
*/
|
||||
return gf_apply_filters( array( 'gform_field_choices', $this->formId, $this->id ), $choices, $this );
|
||||
|
||||
}
|
||||
|
||||
public function get_checked_attribute( $choice, $value, $input_id, $form_id ) {
|
||||
$is_form_editor = $this->is_form_editor();
|
||||
|
||||
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 ) && ! empty( $_POST[ 'is_submit_' . $form_id ] ) ) {
|
||||
$checked = "checked='checked'";
|
||||
} else {
|
||||
$checked = '';
|
||||
}
|
||||
|
||||
return $checked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the aria-describedby attribute for the first choice.
|
||||
*
|
||||
* @since 2.9.0
|
||||
* @access public
|
||||
*
|
||||
* @param int $form_id The current form ID.
|
||||
* @param array $describedby Additional describedby attribute value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_choice_aria_describedby( $form_id, $describedby = array() ) {
|
||||
$limit_describedby = array();
|
||||
|
||||
if ( is_array( $describedby ) ) {
|
||||
$limit_describedby = array_merge( $limit_describedby, $describedby );
|
||||
}
|
||||
|
||||
if ( $this->get_limit_message_text() ) {
|
||||
$limit_describedby[] = 'gfield_choice_limit_message_' . $form_id . '_' . $this->id;
|
||||
}
|
||||
|
||||
return $this->get_aria_describedby( $limit_describedby );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a specific checkbox is checked.
|
||||
*
|
||||
|
||||
@@ -278,7 +278,7 @@ class GF_Field_Date extends GF_Field {
|
||||
$field_position = substr( $format, 0, 3 );
|
||||
if ( $is_form_editor ) {
|
||||
|
||||
$datepicker_display = in_array( $this->dateType, array( 'datefield', 'datedropdown' ) ) ? 'none' : 'block';
|
||||
$datepicker_display = in_array( $this->dateType, array( 'datefield', 'datedropdown' ) ) ? 'none' : 'flex';
|
||||
$datefield_display = $this->dateType == 'datefield' ? 'inline' : 'none';
|
||||
$dropdown_display = $this->dateType == 'datedropdown' ? 'inline' : 'none';
|
||||
$icon_display = $this->calendarIconType == 'calendar' ? 'inline' : 'none';
|
||||
@@ -328,7 +328,7 @@ class GF_Field_Date extends GF_Field {
|
||||
$day_dropdown = "<div class='gfield_date_dropdown_day ginput_date_dropdown ginput_container ginput_container_date gform-grid-col' 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 ginput_container ginput_container_date gform-grid-col' 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 gform-grid-col' 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/datepicker/datepicker.svg' id='gfield_input_datepicker_icon' style='display:$icon_display'/></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/datepicker/datepicker.svg' id='gfield_input_datepicker_icon' style='display:$icon_display'/></div>";
|
||||
|
||||
switch ( $field_position ) {
|
||||
case 'dmy' :
|
||||
@@ -1015,7 +1015,7 @@ class GF_Field_Date extends GF_Field {
|
||||
* @return string
|
||||
*/
|
||||
public function get_field_placeholder_attribute() {
|
||||
if ( $this->dateType === 'datepicker' && empty( $this->placeholder ) ) {
|
||||
if ( empty( $this->placeholder ) ) {
|
||||
$format = $this->is_form_editor() ? wp_strip_all_tags( $this->get_date_format() ) : $this->get_date_format();
|
||||
|
||||
return sprintf( "placeholder='%s'", esc_attr( $format ) );
|
||||
@@ -1086,7 +1086,7 @@ class GF_Field_Date extends GF_Field {
|
||||
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';
|
||||
$filter_settings['cssClass'] = 'datepicker gform-datepicker ymd_dash';
|
||||
|
||||
return $filter_settings;
|
||||
}
|
||||
|
||||
@@ -253,10 +253,6 @@ class GF_Field_FileUpload extends GF_Field {
|
||||
$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;
|
||||
|
||||
// Generate upload rules messages ( allowed extensions, max no. of files, max file size ).
|
||||
$upload_rules_messages = array();
|
||||
// Extensions.
|
||||
@@ -346,7 +342,7 @@ class GF_Field_FileUpload extends GF_Field {
|
||||
$upload = "<div id='{$container_id}' data-settings='{$plupload_init_json}' class='gform_fileupload_multifile'>
|
||||
<div id='{$drag_drop_id}' class='gform_drop_area gform-theme-field-control'>
|
||||
<span class='gform_drop_instructions'>{$drop_files_here_text} </span>
|
||||
<button type='button' id='{$browse_button_id}' class='button gform_button_select_files gform-theme-button gform-theme-button--control' {$describedby} {$tabindex} >{$select_files_text}</button>
|
||||
<button type='button' id='{$browse_button_id}' class='button gform_button_select_files gform-theme-button gform-theme-button--control' {$describedby} {$tabindex} {$disabled_text}>{$select_files_text}</button>
|
||||
</div>
|
||||
</div>";
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ class GF_Field_HiddenProduct extends GF_Field {
|
||||
|
||||
$field_type = $is_entry_detail || $is_form_editor ? 'text' : 'hidden';
|
||||
|
||||
return $quantity_field . $product_name_field . "<input name='input_{$id}.2' id='ginput_base_price_{$form_id}_{$this->id}' type='{$field_type}' value='{$price}' class='gform_hidden ginput_amount' {$disabled_text}/>";
|
||||
return "<div class='ginput_container ginput_container_product_price_hidden'>" . $quantity_field . $product_name_field . "<input name='input_{$id}.2' id='ginput_base_price_{$form_id}_{$this->id}' type='{$field_type}' value='{$price}' class='gform_hidden ginput_amount' {$disabled_text}/></div>";
|
||||
}
|
||||
|
||||
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
require_once( plugin_dir_path( __FILE__ ) . 'class-gf-field-multiple-choice.php' );
|
||||
|
||||
class GF_Field_Image_Choice extends GF_Field_Multiple_Choice {
|
||||
|
||||
public $type = 'image_choice';
|
||||
|
||||
public $checkbox_choice;
|
||||
|
||||
public function get_form_editor_field_title() {
|
||||
return esc_attr__( 'Image Choice', 'gravityforms' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the field's form editor description.
|
||||
*
|
||||
* @since 2.5
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_form_editor_field_description() {
|
||||
return esc_attr__( 'Allow users to choose from a list of images.', 'gravityforms' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the field's form editor icon.
|
||||
*
|
||||
* This could be an icon url or a gform-icon class.
|
||||
*
|
||||
* @since 2.5
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_form_editor_field_icon() {
|
||||
return 'gform-icon--image_choice';
|
||||
}
|
||||
|
||||
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',
|
||||
'enable_multiple_selections_setting',
|
||||
'choice_min_max_setting',
|
||||
'image_choice_ui_show_label_setting'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the choice labels visibility setting default for the image choice field.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param object $field The field object.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_image_choice_label_visibility_setting_default( $form_id ) {
|
||||
/**
|
||||
* A filter that allows for the managing of the default image choice labels visibility setting.
|
||||
* Default is show. Options are 'show' and 'hide'.
|
||||
*
|
||||
* @since 2.9
|
||||
*
|
||||
* @param string $label_visibility_default The default image choice labels visibility.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
return gf_apply_filters( array( 'gform_image_choice_label_visibility_default', $form_id ), 'show' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the choice labels visibility setting for the given image choice field.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param object $field The field object.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_image_choice_label_visibility_setting( $field ) {
|
||||
return $field->imageChoiceLabelVisibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the choice inputs visibility setting for the given image choice field.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param object $field The field object.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_image_choice_input_visibility_setting( $field ) {
|
||||
/**
|
||||
* A filter that allows for the managing of image choice inputs visibility.
|
||||
* Default is show. Options are 'show' and 'hide'.
|
||||
* If image choice labels are hidden, the inputs will also be hidden.
|
||||
*
|
||||
* @since 2.9
|
||||
*
|
||||
* @param string $input_visibility The image choice inputs visibility.
|
||||
* @param object $field The current field object.
|
||||
*/
|
||||
return gf_apply_filters( array( 'gform_image_choice_input_visibility', $field->formId ), 'show', $field );
|
||||
}
|
||||
|
||||
public function get_form_editor_inline_script_on_page_render() {
|
||||
// Set the field settings default values
|
||||
$js = sprintf( '
|
||||
function SetDefaultValues_%1$s( field ) {
|
||||
if ( ! field.imageChoiceLabelVisibility ) {
|
||||
field.imageChoiceLabelVisibility = "%2$s";
|
||||
}
|
||||
};',
|
||||
$this->type,
|
||||
self::get_image_choice_label_visibility_setting_default( rgget( 'id' ) )
|
||||
) . PHP_EOL;
|
||||
|
||||
// Initialize the field settings values
|
||||
$js .= 'jQuery( document ).on( "gform_load_field_settings", function( event, field, form ) {
|
||||
if ( field.type !== "image_choice" ) {
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById("image_choice_ui_show_label").value = field.imageChoiceLabelVisibility;
|
||||
|
||||
if ( field.type === "image_choice" && field.imageChoiceLabelVisibility === "hide" ) {
|
||||
SetFieldAccessibilityWarning( "image_choice_ui_show_label_setting", "above" );
|
||||
}
|
||||
} );' . PHP_EOL;
|
||||
|
||||
// Update the field settings values on change of the setting
|
||||
$js .= 'function SetFieldImageChoiceLabelVisibility( visibility ) {
|
||||
SetFieldProperty( "imageChoiceLabelVisibility", visibility );
|
||||
|
||||
if ( visibility === "hide" ) {
|
||||
SetFieldAccessibilityWarning( "image_choice_ui_show_label_setting", "above" );
|
||||
} else {
|
||||
ResetFieldAccessibilityWarning( "image_choice_ui_show_label_setting" );
|
||||
}
|
||||
|
||||
RefreshSelectedFieldPreview();
|
||||
}' . PHP_EOL;
|
||||
|
||||
return $js;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the image URL for a choice to display in a merge tage with the "img_url" modifier.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param string $value The value of the merge tag.
|
||||
* @param string $input_id The ID of the input.
|
||||
* @param array $entry The entry currently being processed.
|
||||
* @param array $form The form currently being processed.
|
||||
* @param object $field The field currently being processed.
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
public function get_merge_tag_img_url( $value, $input_id, $entry, $form, $field ) {
|
||||
if ( ! is_array( $field->choices ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
foreach ( $field->choices as $choice ) {
|
||||
if ( is_array( $value ) && GFFormsModel::choice_value_match( $field, $choice, $value[ $input_id ] ) ) {
|
||||
return rgar( $choice, 'file_url' ) ? $choice['file_url'] : '';
|
||||
} else if ( ! is_array( $value ) && GFFormsModel::choice_value_match( $field, $choice, $value ) ) {
|
||||
return rgar( $choice, 'file_url' ) ? $choice['file_url'] : '';
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GF_Fields::register( new GF_Field_Image_Choice() );
|
||||
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
class GF_Field_Multiple_Choice extends GF_Field {
|
||||
|
||||
public $type = 'multi_choice';
|
||||
|
||||
public function get_form_editor_field_title() {
|
||||
return esc_attr__( 'Multiple Choice', 'gravityforms' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the field's form editor description.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_form_editor_field_description() {
|
||||
return esc_attr__( 'Allow users to choose from a list of options.', 'gravityforms' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the field's form editor icon.
|
||||
*
|
||||
* This could be an icon url or a gform-icon class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_form_editor_field_icon() {
|
||||
return 'gform-icon--choice';
|
||||
}
|
||||
|
||||
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_text_setting',
|
||||
'choice_min_max_setting',
|
||||
'horizontal_vertical_setting',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the "select all" choice markup for the choice field.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param $value
|
||||
* @param $tabindex
|
||||
* @param $selected_choices_count
|
||||
* @return string The select all choice markup.
|
||||
*/
|
||||
public function get_choice_field_select_all_markup( $value, $tabindex, $selected_choices_count ) {
|
||||
if ( isset( $this->choiceLimit ) && $this->choiceLimit !== 'unlimited' && $this->choiceLimit !== 'range' ) {
|
||||
return '';
|
||||
}
|
||||
$select_label = isset( $this->selectAllText ) ? esc_html( $this->selectAllText ) : esc_html__( 'Select All', 'gravityforms' );
|
||||
$disabled_text = $this->is_form_editor() ? 'disabled="disabled"' : '';
|
||||
|
||||
// Prepare choice ID.
|
||||
$id = 'choice_' . $this->id . '_select_all';
|
||||
|
||||
// Determine if all checkboxes are selected.
|
||||
if ( $selected_choices_count === count( $this->choices ) ) {
|
||||
$checked = ' checked="checked"';
|
||||
} else {
|
||||
$checked = '';
|
||||
}
|
||||
|
||||
$checkbox = new GF_Field_Checkbox( $this );
|
||||
$aria_describedby = $checkbox->get_choice_aria_describedby( $this->formId );
|
||||
|
||||
// Prepare choice markup.
|
||||
$choice_markup = "<div class='gchoice gchoice_select_all'>
|
||||
<input class='gfield-choice-input gfield_choice_all_toggle' type='checkbox' id='{$id}' {$tabindex} {$aria_describedby} onclick='gformToggleCheckboxes( this )' onkeypress='gformToggleCheckboxes( this )'{$checked} {$disabled_text} />
|
||||
<label for='{$id}' id='label_" . $this->id . "_select_all' class='gform-field-label gform-field-label--type-inline' data-label-select='{$select_label}''>{$select_label}</label>
|
||||
</div>";
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
$select_all = gf_apply_filters( array( 'gform_field_choice_markup_pre_render', $this->formId, $this->id ), $choice_markup, array(), $this, $value );
|
||||
|
||||
return $select_all;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the choice alignment for the given field.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param object $field The field object.
|
||||
* @return string
|
||||
*/
|
||||
public static function get_field_choice_alignment( $field ) {
|
||||
|
||||
return rgempty( 'choiceAlignment', $field ) ? self::get_default_choice_alignment( $field ) : $field->choiceAlignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default choice alignment for the multi_choice field.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param object $field The field object.
|
||||
* @return string
|
||||
*/
|
||||
public static function get_default_choice_alignment( $field) {
|
||||
/*
|
||||
* Filter the default choice alignment. Default is vertical. Options are 'vertical' and 'horizontal'.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param string $default_choice_alignment The default choice alignment.
|
||||
* @param object $field The field.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
return gf_apply_filters( array( 'gform_default_choice_alignment', $field->formId ), 'vertical', $field );
|
||||
}
|
||||
|
||||
public function get_form_editor_inline_script_on_page_render() {
|
||||
$alignment = self::get_default_choice_alignment( $this );
|
||||
return "gform.addAction( 'gform_post_load_field_settings', function( [ field, form ] ) { if( '" . $alignment . "' == 'horizontal' ) { jQuery('#choice_alignment_horizontal').prop('checked', true); } else { jQuery('#choice_alignment_vertical').prop('checked', true); } } );";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GF_Fields::register( new GF_Field_Multiple_Choice() );
|
||||
@@ -82,15 +82,14 @@ class GF_Field_Post_Tags extends GF_Field {
|
||||
$aria_describedby = $this->get_aria_describedby();
|
||||
|
||||
// Use the WordPress built-in class "howto" in the form editor.
|
||||
$text_hint_class = $is_form_editor ? 'howto' : 'gfield_post_tags_hint gfield_description';
|
||||
$text_hint = '<p class="' . $text_hint_class . '" id="' . $field_id . '_desc">' . gf_apply_filters( array(
|
||||
$text_hint = '<p class="gfield_post_tags_hint gfield_description" id="' . $field_id . '_desc">' . gf_apply_filters( array(
|
||||
'gform_post_tags_hint',
|
||||
$form_id,
|
||||
$this->id,
|
||||
), esc_html__( 'Separate tags with commas', 'gravityforms' ), $form_id ) . '</p>';
|
||||
|
||||
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}/> {$text_hint}
|
||||
<input name='input_{$id}' id='{$field_id}' type='text' value='{$value}' class='{$class}' {$tabindex} {$placeholder_attribute} {$required_attribute} {$invalid_attribute} {$aria_describedby} {$disabled_text}/>{$text_hint}
|
||||
</div>";
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
require_once( plugin_dir_path( __FILE__ ) . 'field-decorator-choice/class-gf-field-decorator-choice-radio-markup.php' );
|
||||
|
||||
class GF_Field_Radio extends GF_Field {
|
||||
|
||||
@@ -117,6 +118,11 @@ class GF_Field_Radio extends GF_Field {
|
||||
|
||||
public function get_field_input( $form, $value = '', $entry = null ) {
|
||||
|
||||
if ( $this->type == 'image_choice' ) {
|
||||
$this->image_markup = new GF_Field_Decorator_Choice_Radio_Markup( $this );
|
||||
return $this->image_markup->get_field_input( $form, $value, $entry );
|
||||
}
|
||||
|
||||
$form_id = $form['id'];
|
||||
$is_entry_detail = $this->is_entry_detail();
|
||||
$is_form_editor = $this->is_form_editor();
|
||||
@@ -145,6 +151,17 @@ class GF_Field_Radio extends GF_Field {
|
||||
$choice_id = 0;
|
||||
$count = 1;
|
||||
|
||||
/**
|
||||
* A filter that allows for the setting of the maximum number of choices shown in
|
||||
* the form editor for choice based fields (radio, checkbox, image, and multiple choice).
|
||||
*
|
||||
* @since 2.9
|
||||
*
|
||||
* @param int $max_choices_visible_count The default number of choices visible is 5.
|
||||
* @param object $field The current field object.
|
||||
*/
|
||||
$max_choices_count = gf_apply_filters( array( 'gform_field_choices_max_count_visible', $form_id ), 5, $this );
|
||||
|
||||
$tag = GFCommon::is_legacy_markup_enabled( $form_id ) ? 'li' : 'div';
|
||||
|
||||
foreach ( $field_choices as $choice ) {
|
||||
@@ -157,7 +174,7 @@ class GF_Field_Radio extends GF_Field {
|
||||
|
||||
$choices .= $this->get_choice_html( $choice, $choice_id, $value, $disabled_text, $is_admin );
|
||||
|
||||
if ( $is_form_editor && $count >= 5 ) {
|
||||
if ( $is_form_editor && $count >= $max_choices_count ) {
|
||||
$editor_limited = true;
|
||||
break;
|
||||
}
|
||||
@@ -182,7 +199,7 @@ class GF_Field_Radio extends GF_Field {
|
||||
|
||||
$total = sizeof( $field_choices );
|
||||
if ( $is_form_editor && ( $count < $total ) ) {
|
||||
$choices .= "<{$tag} class='gchoice_total'>" . sprintf( esc_html__( '%d of %d items shown. Edit field to view all', 'gravityforms' ), $count, $total ) . "</{$tag}>";
|
||||
$choices .= "<{$tag} class='gchoice_total'><span>" . sprintf( esc_html__( '%d of %d items shown. Edit choices to view all.', 'gravityforms' ), $count, $total ) . "</span></{$tag}>";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,8 +208,8 @@ class GF_Field_Radio extends GF_Field {
|
||||
*
|
||||
* @since unknown
|
||||
*
|
||||
* @param string $choices The choices HTML.
|
||||
* @param GF_Field_Radio $field The current field object.
|
||||
* @param string $choices The choices HTML.
|
||||
* @param object $field The current field object.
|
||||
*/
|
||||
return gf_apply_filters( array( 'gform_field_choices', $this->formId ), $choices, $this );
|
||||
}
|
||||
@@ -449,6 +466,7 @@ class GF_Field_Radio extends GF_Field {
|
||||
$use_value = in_array( 'value', $modifiers );
|
||||
$format_currency = ! $use_value && in_array( 'currency', $modifiers );
|
||||
$use_price = $format_currency || ( ! $use_value && in_array( 'price', $modifiers ) );
|
||||
$image_url = in_array( 'img_url', $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.
|
||||
@@ -461,20 +479,32 @@ class GF_Field_Radio extends GF_Field {
|
||||
$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 );
|
||||
switch (true) {
|
||||
case $use_value:
|
||||
list( $val, $price ) = rgexplode( '|', $item, 2 );
|
||||
break;
|
||||
|
||||
$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 );
|
||||
case $use_price:
|
||||
list( $name, $val ) = rgexplode( '|', $item, 2 );
|
||||
if ( $format_currency ) {
|
||||
$val = GFCommon::to_money( $val, rgar( $entry, 'currency' ) );
|
||||
}
|
||||
break;
|
||||
|
||||
case $image_url:
|
||||
$image_choice = new GF_Field_Image_Choice( $this );
|
||||
$val = $image_choice->get_merge_tag_img_url( $raw_value, $input_id, $entry, $form, $this );
|
||||
break;
|
||||
|
||||
case $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;
|
||||
break;
|
||||
|
||||
default:
|
||||
$val = RGFormsModel::is_field_hidden( $form, $this, array(), $entry ) ? '' : RGFormsModel::get_choice_text( $this, $raw_value, $input_id );
|
||||
break;
|
||||
}
|
||||
|
||||
$ary[] = GFCommon::format_variable_value( $val, $url_encode, $esc_html, $format );
|
||||
@@ -551,6 +581,17 @@ class GF_Field_Radio extends GF_Field {
|
||||
return $operators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to return null instead of the array of inputs in case this is a choice field.
|
||||
*
|
||||
* @since 2.9
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function get_entry_inputs() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GF_Fields::register( new GF_Field_Radio() );
|
||||
|
||||
@@ -191,7 +191,19 @@ class GF_Field_Repeater extends GF_Field {
|
||||
$prefix = $sub_field->id . '_';
|
||||
}
|
||||
|
||||
$field_items = $this->flatten( $values, $prefix, $sub_field->is_value_submission_array() );
|
||||
if ( $sub_field instanceof GF_Field_List ) {
|
||||
// List field expects an array. If we flatten the List Field values, we end up adding extra repeater items instead of populating the list.
|
||||
if ( is_array( $values ) && is_array( $values[0] ) ) {
|
||||
$field_items = array();
|
||||
foreach ( $values as $key => $value ) {
|
||||
$field_items[ $prefix . $key ] = $value;
|
||||
}
|
||||
} else {
|
||||
$field_items = array( $prefix . '0' => $values );
|
||||
}
|
||||
} else {
|
||||
$field_items = $this->flatten( is_array( $values ) ? $values : array( $values ), $prefix, $sub_field->is_value_submission_array() );
|
||||
}
|
||||
}
|
||||
$items = array_merge( $items, $field_items );
|
||||
}
|
||||
@@ -692,6 +704,8 @@ class GF_Field_Repeater extends GF_Field {
|
||||
|
||||
$repeater_fields = array();
|
||||
|
||||
$is_new_entry = empty( $_POST[ 'is_submit_' . $this->formId ] ) && ! array_key_exists( 'id', $entry );
|
||||
|
||||
foreach ( $repeater_field->fields as $field ) {
|
||||
if ( is_array( $field->fields ) ) {
|
||||
$repeater_fields[] = $field;
|
||||
@@ -706,7 +720,7 @@ class GF_Field_Repeater extends GF_Field {
|
||||
|
||||
$input_id = $input['id'];
|
||||
|
||||
$key = $input_id . $index . '_' . $i;
|
||||
$key = $input_id . $index . ( $is_new_entry ? '' : '_' . $i );
|
||||
|
||||
$value = isset( $entry[ $key ] ) ? $entry[ $key ] : '';
|
||||
|
||||
|
||||
@@ -154,13 +154,15 @@ class GF_Field_Submit extends GF_Field {
|
||||
$form_id = absint( $form['id'] );
|
||||
$is_form_editor = $this->is_form_editor();
|
||||
|
||||
$class = esc_attr( 'gform-button gform-button--white ' );
|
||||
$class_theme = $is_form_editor ? esc_attr( 'gform-theme-button gform-theme-button--secondary ' ) : '';
|
||||
$class = sprintf( '%s%s', esc_attr( 'gform-button gform-button--white ' ), $class_theme );
|
||||
$default_text = __( 'Submit', 'gravityforms' );
|
||||
$button = rgar( $form, 'button', array( 'type' => 'link' ) );
|
||||
|
||||
$inline = rgar( $form['button'], 'location', 'bottom' );
|
||||
|
||||
// If we're in the editor or the button is inline, display the button. Otherwise, the button will be added to the footer in form_display.php.
|
||||
// If we're in the editor or the button is inline, display the button.
|
||||
// Otherwise, the button will be added to the footer in form_display.php.
|
||||
if ( $is_form_editor || 'inline' == $inline ) {
|
||||
$submit = GFFormDisplay::get_form_button( $form_id, "gform_submit_button_{$form_id}", $button, $default_text, $class, $default_text, 0 );
|
||||
return gf_apply_filters( array( 'gform_submit_button', $form_id ), $submit, $form );
|
||||
|
||||
@@ -119,15 +119,14 @@ class GF_Field_Text extends GF_Field {
|
||||
// For Post Tags, Use the WordPress built-in class "howto" in the form editor.
|
||||
$text_hint = '';
|
||||
if ( $this->type === 'post_tags' ) {
|
||||
$text_hint_class = $is_form_editor ? 'howto' : 'gfield_post_tags_hint gfield_description';
|
||||
$text_hint = '<p class="' . $text_hint_class . '" id="' . $field_id . '_desc">' . gf_apply_filters( array(
|
||||
$text_hint = '<p class="gfield_post_tags_hint gfield_description" id="' . $field_id . '_desc">' . gf_apply_filters( array(
|
||||
'gform_post_tags_hint',
|
||||
$form_id,
|
||||
$this->id,
|
||||
), esc_html__( 'Separate tags with commas', 'gravityforms' ), $form_id ) . '</p>';
|
||||
}
|
||||
|
||||
$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} {$autocomplete} /> {$text_hint}";
|
||||
$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} {$autocomplete} />{$text_hint}";
|
||||
|
||||
return sprintf( "<div class='ginput_container ginput_container_text'>%s</div>", $input );
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ class GF_Field_Textarea extends GF_Field {
|
||||
$display = $this->useRichTextEditor ? 'block' : 'none';
|
||||
$input_style = $this->useRichTextEditor ? 'style="display:none;"' : '';
|
||||
$size = $this->size ? $this->size : 'medium';
|
||||
$input = "<div id='{$field_id}_rte_preview' class='gform-rte-preview {$size}' style='display:{$display}'>
|
||||
$input = "<div id='{$field_id}_rte_preview' class='gform-rte-preview gform-theme__disable {$size}' style='display:{$display}'>
|
||||
<ul class='rte_preview_header'>
|
||||
<li class='icon'><svg width='24' height='24' viewBox='0 0 24 24' version='1.1' xmlns='http://www.w3.org/2000/svg'><path d='M7.761 19c-.253 0-.44-.06-.56-.18-.12-.12-.18-.307-.18-.56l-.02-12.52c0-.267.08-.457.2-.57.12-.113.307-.17.56-.17h5.019c1.56 0 2.723.317 3.49.95.767.633 1.15 1.497 1.15 2.59 0 .667-.21 1.283-.63 1.85-.42.567-.937.963-1.55 1.19l.02.08c.387.067.793.247 1.22.54.427.293.787.677 1.08 1.15.293.473.44 1.01.44 1.61 0 1.32-.427 2.323-1.28 3.01-.853.687-2.12 1.03-3.8 1.03H7.761zm4.969-8.26c.687 0 1.237-.17 1.65-.51.414-.34.621-.77.621-1.29 0-1.147-.757-1.72-2.271-1.72H9.28v3.52h3.45zm.59 6.02c.725 0 1.283-.17 1.674-.51.39-.34.586-.823.586-1.45 0-.587-.223-1.037-.67-1.35-.446-.313-1.088-.47-1.925-.47H9.28v3.78h4.04z' fill='#555d66' stroke='none' stroke-width='1' fill-rule='evenodd'/></svg></li>
|
||||
<li class='icon'><svg width='24' height='24' viewBox='0 0 24 24' ersion='1.1' xmlns='http://www.w3.org/2000/svg'><path d='M16.746 4.723l-.176.84h-.263c-.638 0-1.097.12-1.377.36-.28.242-.47.6-.567 1.075l-2.07 9.805c-.059.28-.088.465-.088.556 0 .534.482.801 1.445.801h.254l-.175.84h-5.82l.155-.84h.264c1.107 0 1.761-.478 1.963-1.435l2.08-9.805c.052-.247.078-.433.078-.557 0-.534-.482-.8-1.445-.8h-.254l.176-.84h5.82z' fill='#555d66' stroke='none' stroke-width='1' fill-rule='evenodd'/></svg></li>
|
||||
|
||||
@@ -62,6 +62,17 @@ class GF_Field extends stdClass implements ArrayAccess {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the choice field has entries that persist after changing the field type.
|
||||
*
|
||||
* @since 2.9
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function has_persistent_choices() {
|
||||
return in_array( $this->type, array( 'multi_choice', 'image_choice' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires the deprecation notice only once per page. Not fired during AJAX requests.
|
||||
*
|
||||
@@ -330,6 +341,26 @@ class GF_Field extends stdClass implements ArrayAccess {
|
||||
return 'gform-icon--cog';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the form editor icon for the field type.
|
||||
*
|
||||
* Sometimes the field type and the input type are not the same, but we want the field type icon.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_form_editor_field_type_icon() {
|
||||
if ( $this->type !== $this->inputType ) {
|
||||
$field_class = GF_Fields::get( $this->type );
|
||||
if ( $field_class ) {
|
||||
return $field_class->get_form_editor_field_icon();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->get_form_editor_field_icon();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the field's form editor description.
|
||||
*
|
||||
@@ -550,8 +581,7 @@ class GF_Field extends stdClass implements ArrayAccess {
|
||||
$disable_ajax_reload = $this->disable_ajax_reload();
|
||||
$ajax_reload_id = $disable_ajax_reload === 'skip' || $disable_ajax_reload === 'true' || $disable_ajax_reload === true ? 'true' : esc_attr( rgar( $atts, 'id' ) );
|
||||
$is_form_editor = $this->is_form_editor();
|
||||
|
||||
$target_input_id = esc_attr( rgar( $atts, 'id' ) );
|
||||
$target_input_id = esc_attr( rgar( $atts, 'id' ) );
|
||||
|
||||
// Get the field sidebar messages, this could be an array of messages or a warning message string.
|
||||
$field_sidebar_messages = GFCommon::is_form_editor() ? $this->get_field_sidebar_messages() : '';
|
||||
@@ -565,7 +595,7 @@ class GF_Field extends stdClass implements ArrayAccess {
|
||||
}
|
||||
|
||||
if ( ! empty( $sidebar_message_content ) ) {
|
||||
$atts['class'] .= ' gfield_' . ( $sidebar_message_type === 'error' ? 'warning' : $sidebar_message_type );
|
||||
$atts['class'] .= ' gfield-has-sidebar-message gfield-has-sidebar-message--type-' . ( $sidebar_message_type === 'error' ? 'warning' : $sidebar_message_type );
|
||||
if ( $sidebar_message_type === 'error' ) {
|
||||
$atts['aria-invalid'] = 'true';
|
||||
}
|
||||
@@ -583,7 +613,7 @@ class GF_Field extends stdClass implements ArrayAccess {
|
||||
rgar( $atts, 'data-field-position' ) ? ' data-field-position="' . esc_attr( $atts['data-field-position'] ) . '"' : '',
|
||||
$ajax_reload_id,
|
||||
rgar( $atts, 'aria-invalid' ) ? ' aria-invalid="true"' : '',
|
||||
empty( $sidebar_message_content ) ? '' : '<span class="field-' . $sidebar_message_type . '-message-content hidden">' . \GFCommon::maybe_wp_kses( $sidebar_message_content ) . '</span>'
|
||||
empty( $sidebar_message_content ) ? '' : '<span class="field-sidebar-message-content field-sidebar-message-content--type-' . $sidebar_message_type . ' hidden">' . \GFCommon::maybe_wp_kses( $sidebar_message_content ) . '</span>'
|
||||
);
|
||||
|
||||
}
|
||||
@@ -652,7 +682,16 @@ class GF_Field extends stdClass implements ArrayAccess {
|
||||
} else {
|
||||
$label = wp_strip_all_tags( $this->get_field_label( true, '' ) );
|
||||
}
|
||||
return sprintf( '%1$s - %2$s, %3$s.', esc_attr( $label ), esc_attr( $this->type ), esc_attr( $action ) );
|
||||
|
||||
// Sometimes the field editor label is different from the field type, so make sure we're using the correct field type.
|
||||
$field_class = GF_Fields::get( $this->type );
|
||||
if ( is_object( $field_class ) ) {
|
||||
$field_title = $field_class->get_form_editor_field_title();
|
||||
} else {
|
||||
$field_title = $this->type;
|
||||
}
|
||||
|
||||
return sprintf( '%1$s - %2$s, %3$s.', esc_attr( $label ), esc_attr( $field_title ), esc_attr( $action ) );
|
||||
}
|
||||
|
||||
// # SUBMISSION -----------------------------------------------------------------------------------------------------
|
||||
@@ -668,6 +707,50 @@ class GF_Field extends stdClass implements ArrayAccess {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the input ID given the choice key for Multiple Choice and Image Choice fields.
|
||||
*
|
||||
* @since 2.9
|
||||
*
|
||||
* @param string $key The choice key.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_input_id_from_choice_key( $key ) {
|
||||
$input_id = '';
|
||||
if ( is_array( $this->inputs ) ) {
|
||||
foreach ( $this->inputs as $input ) {
|
||||
if ( rgar( $input, 'key' ) == $key ) {
|
||||
$input_id = rgar( $input, 'id' );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $input_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the choice ID given the input key for Multiple Choice and Image Choice fields.
|
||||
*
|
||||
* @since 2.9
|
||||
*
|
||||
* @param string $key The choice key.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_choice_id_from_input_key( $key ) {
|
||||
$choice_id = '';
|
||||
if ( is_array( $this->choices ) ) {
|
||||
foreach ( $this->choices as $index => $choice ) {
|
||||
if ( rgar( $choice, 'key' ) == $key ) {
|
||||
$choice_id = $index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $choice_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to determine the required validation result.
|
||||
*
|
||||
@@ -679,7 +762,8 @@ class GF_Field extends stdClass implements ArrayAccess {
|
||||
|
||||
$copy_values_option_activated = $this->enableCopyValuesOption && rgpost( 'input_' . $this->id . '_copy_values_activated' );
|
||||
|
||||
if ( is_array( $this->inputs ) ) {
|
||||
// GF_Field_Radio can now have inputs if it's a Choice or Image Choice field
|
||||
if ( is_array( $this->inputs ) && ! ( $this instanceof GF_Field_Radio ) ) {
|
||||
foreach ( $this->inputs as $input ) {
|
||||
|
||||
if ( $copy_values_option_activated ) {
|
||||
@@ -1662,7 +1746,7 @@ class GF_Field extends stdClass implements ArrayAccess {
|
||||
$drag_handle = '';
|
||||
}
|
||||
|
||||
$field_icon = '<span class="gfield-field-action gfield-icon" title="' . $this->get_form_editor_field_title() . '">' . GFCommon::get_icon_markup( array( 'icon' => $this->get_form_editor_field_icon() ) ) . '</span>';
|
||||
$field_icon = '<span class="gfield-field-action gfield-icon" title="' . $this->get_form_editor_field_title() . '">' . GFCommon::get_icon_markup( array( 'icon' => $this->get_form_editor_field_type_icon() ) ) . '</span>';
|
||||
|
||||
$field_id = '<span class="gfield-compact-icon--id">' . sprintf( esc_html__( 'ID: %s', 'gravityforms' ), $this->id ) . '</span>';
|
||||
|
||||
@@ -1671,21 +1755,30 @@ class GF_Field extends stdClass implements ArrayAccess {
|
||||
|
||||
$field_sidebar_messages = $this->get_field_sidebar_messages();
|
||||
$sidebar_message = is_array( rgar( $field_sidebar_messages, '0' ) ) ? array_shift( $field_sidebar_messages ) : $field_sidebar_messages;
|
||||
$compact_view_warning_icon = '';
|
||||
$compact_view_sidebar_message_icon = '';
|
||||
if ( ! empty( $sidebar_message ) ) {
|
||||
$compact_view_warning_icon = rgar( $sidebar_message, 'type' ) === 'warning' || ! is_array( $sidebar_message ) ? '<span class="gform-icon gform-icon--exclamation-simple gform-icon--preset-active gform-icon-preset--status-error gform-compact-view-warning-icon" ></span>' : '';
|
||||
$sidebar_message_types = array(
|
||||
'warning' => array( 'gform-icon--exclamation-simple', 'gform-icon-preset--status-error' ),
|
||||
'error' => array( 'gform-icon--exclamation-simple', 'gform-icon-preset--status-error' ),
|
||||
'info' => array( 'gform-icon--information-simple', 'gform-icon-preset--status-info' ),
|
||||
'notice' => array( 'gform-icon--information-simple', 'gform-icon-preset--status-info' ),
|
||||
'success' => array( 'gform-icon--checkmark-simple', 'gform-icon-preset--status-correct' ),
|
||||
);
|
||||
$compact_view_sidebar_message_icon_type = is_array( $field_sidebar_messages ) ? rgar( $sidebar_message, 'type' ) : 'warning';
|
||||
$compact_view_sidebar_message_icon_helper_text = is_array( $field_sidebar_messages ) ? rgar( $sidebar_message, 'icon_helper_text' ) : __( 'This field has an issue', 'gravityforms' );
|
||||
$compact_view_sidebar_message_icon = sprintf( '<span class="gfield-sidebar-message-icon gform-icon gform-icon--preset-active %1$s" title="%2$s" aria-label="%2$s"></span>', implode( ' ', $sidebar_message_types[ $compact_view_sidebar_message_icon_type ] ), esc_attr( $compact_view_sidebar_message_icon_helper_text ) );
|
||||
}
|
||||
|
||||
$admin_buttons = "
|
||||
<div class='gfield-admin-icons'>
|
||||
<div class='gfield-admin-icons gform-theme__disable'>
|
||||
{$drag_handle}
|
||||
{$duplicate_field_link}
|
||||
{$edit_field_link}
|
||||
{$delete_field_link}
|
||||
{$compact_view_warning_icon}
|
||||
{$compact_view_sidebar_message_icon}
|
||||
{$field_icon}
|
||||
</div>
|
||||
<div class='gfield-compact-icons'>
|
||||
<div class='gfield-compact-icons gform-theme__disable'>
|
||||
{$field_id}
|
||||
{$conditional}
|
||||
</div>";
|
||||
@@ -1713,7 +1806,7 @@ class GF_Field extends stdClass implements ArrayAccess {
|
||||
*/
|
||||
public function get_hidden_admin_markup() {
|
||||
|
||||
return "<div class='admin-hidden-markup'><i class='gform-icon gform-icon--hidden'></i><span>Hidden</span></div>";
|
||||
return '<div class="admin-hidden-markup"><i class="gform-icon gform-icon--hidden" aria-hidden="true" title="'. esc_attr( __( 'This field is hidden when viewing the form', 'gravityforms' ) ) .'"></i><span>'. esc_attr( __( 'This field is hidden when viewing the form', 'gravityforms' ) ) .'</span></div>';
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
require_once( plugin_dir_path( __FILE__ ) . 'class-gf-field-decorator-choice.php' );
|
||||
|
||||
class GF_Field_Decorator_Choice_Checkbox_Markup extends ChoiceDecorator {
|
||||
|
||||
public function get_field_input( $form, $value = '', $entry = null ) {
|
||||
$form_id = absint( $form['id'] );
|
||||
|
||||
$is_entry_detail = $this->field->is_entry_detail();
|
||||
$is_form_editor = $this->field->is_form_editor();
|
||||
|
||||
$id = $this->field->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"' : '';
|
||||
$limit_message = $this->get_limit_message();
|
||||
|
||||
$image_style_classes = $this->get_field_classes( $form_id, $this->field );
|
||||
|
||||
// Get checkbox choices markup.
|
||||
$choices_markup = $this->get_checkbox_choices( $value, $disabled_text, $form, $field_id );
|
||||
|
||||
return sprintf(
|
||||
"<div class='ginput_container ginput_container_checkbox ginput_container_image_choice %s'>%s%s</div>",
|
||||
$image_style_classes,
|
||||
$limit_message,
|
||||
$choices_markup
|
||||
);
|
||||
}
|
||||
|
||||
public function get_checkbox_choices( $value, $disabled_text, $form, $field_id ) {
|
||||
$form_id = absint( $form['id'] );
|
||||
|
||||
if ( GFCommon::is_legacy_markup_enabled( $form_id ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$choices = '';
|
||||
$is_entry_detail = $this->field->is_entry_detail();
|
||||
$is_form_editor = $this->field->is_form_editor();
|
||||
|
||||
if ( is_array( $this->field->choices ) ) {
|
||||
|
||||
$choice_number = 1;
|
||||
$count = 1;
|
||||
|
||||
/**
|
||||
* A filter that allows for the setting of the maximum number of choices shown in
|
||||
* the form editor for choice based fields (radio, checkbox, image, and multiple choice).
|
||||
*
|
||||
* @since 2.9
|
||||
*
|
||||
* @param int $max_choices_visible_count The default number of choices visible is 8.
|
||||
* @param object $field The current field object.
|
||||
*/
|
||||
$max_choices_count = gf_apply_filters( array( 'gform_field_choices_max_count_visible', $this->field->formId ), 8, $this->field );
|
||||
|
||||
$choices .= sprintf( '<div class="gfield_checkbox" id="%s">', esc_attr( $field_id ) );
|
||||
|
||||
foreach ( $this->field->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.
|
||||
if ( $is_entry_detail || $is_form_editor || $form_id == 0 ) {
|
||||
$id = $this->field->id . '_' . $choice_number;
|
||||
} else {
|
||||
$id = $form_id . '_' . $this->field->id . '_' . $choice_number;
|
||||
}
|
||||
|
||||
// Handling of input/image aria-describedby
|
||||
$image = $this->get_image_markup( $choice, $id, $choice_number, $form );
|
||||
$image_aria_describedby = 'gchoice_image_' . $id;
|
||||
$aria_describedby = '';
|
||||
|
||||
if ( $choice_number === 1 ) {
|
||||
$image_aria_describedby = $image_aria_describedby ? array( $image_aria_describedby ) : array();
|
||||
$aria_describedby = $this->field->get_choice_aria_describedby( $form_id, $image_aria_describedby );
|
||||
} elseif ( $image_aria_describedby ) {
|
||||
$aria_describedby = sprintf( 'aria-describedby="%s"', $image_aria_describedby );
|
||||
}
|
||||
|
||||
$choice_number ++;
|
||||
|
||||
// Prepare choice attributes.
|
||||
$input_id = $this->get_input_id_from_choice_key( $choice['key'] );
|
||||
$checked = $this->field->get_checked_attribute( $choice, $value, $input_id, $form_id );
|
||||
$tabindex = $this->field->get_tabindex();
|
||||
$choice_value = $choice['value'];
|
||||
|
||||
if ( $this->field->enablePrice ) {
|
||||
$price = rgempty( 'price', $choice ) ? 0 : GFCommon::to_number( rgar( $choice, 'price' ) );
|
||||
$choice_value .= '|' . $price;
|
||||
}
|
||||
|
||||
$choice_value = esc_attr( $choice_value );
|
||||
$choice_markup = "<div class='gchoice gchoice_{$id}'>
|
||||
<span class='gfield-image-choice-wrapper-outer'>
|
||||
{$image}
|
||||
<span class='gfield-image-choice-wrapper-inner'>
|
||||
<input class='gfield-choice-input' name='input_{$input_id}' type='checkbox' value='{$choice_value}' {$checked} id='choice_{$id}' {$tabindex} {$disabled_text} {$aria_describedby}/>
|
||||
<label for='choice_{$id}' id='label_{$id}' class='gform-field-label gform-field-label--type-inline'>
|
||||
{$choice['text']}
|
||||
</label>
|
||||
</span>
|
||||
</span>
|
||||
</div>";
|
||||
|
||||
/**
|
||||
* 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->field->formId,
|
||||
$this->field->id
|
||||
), $choice_markup, $choice, $this->field, $value );
|
||||
|
||||
$is_admin = $is_entry_detail || $is_form_editor;
|
||||
|
||||
if ( $is_admin && rgget( 'view' ) != 'entry' && $count >= $max_choices_count ) {
|
||||
break;
|
||||
}
|
||||
|
||||
$count ++;
|
||||
}
|
||||
|
||||
$choices .= '</div>';
|
||||
|
||||
$total = sizeof( $this->field->choices );
|
||||
|
||||
if ( $count < $total ) {
|
||||
$choices .= "<div class='gchoice_total'><span>"
|
||||
. sprintf( esc_html__( '%d of %d items shown. Edit choices to view all.', 'gravityforms' ), $count, $total ) .
|
||||
"</span></div>";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 The field currently being processed.
|
||||
*/
|
||||
return gf_apply_filters( array( 'gform_field_choices', $this->field->formId ), $choices, $this->field );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
require_once( plugin_dir_path( __FILE__ ) . 'class-gf-field-decorator-choice.php' );
|
||||
|
||||
class GF_Field_Decorator_Choice_Radio_Markup extends ChoiceDecorator {
|
||||
|
||||
public function get_field_input( $form, $value = '', $entry = null ) {
|
||||
$form_id = $form['id'];
|
||||
$is_entry_detail = $this->field->is_entry_detail();
|
||||
$is_form_editor = $this->field->is_form_editor();
|
||||
|
||||
$id = $this->field->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"' : '';
|
||||
|
||||
$image_style_classes = $this->get_field_classes( $form_id, $this->field );
|
||||
|
||||
return sprintf( "<div class='ginput_container ginput_container_radio ginput_container_image_choice {$image_style_classes}'>%s</div>", $this->get_radio_choices( $value, $disabled_text, $form, $field_id ) );
|
||||
}
|
||||
|
||||
public function get_radio_choices( $value, $disabled_text, $form, $field_id ) {
|
||||
$choices = '';
|
||||
|
||||
if ( is_array( $this->field->choices ) ) {
|
||||
$is_entry_detail = $this->field->is_entry_detail();
|
||||
$is_form_editor = $this->field->is_form_editor();
|
||||
$is_admin = $is_entry_detail || $is_form_editor;
|
||||
|
||||
$field_choices = $this->field->choices;
|
||||
$needs_other_choice = $this->field->enableOtherChoice;
|
||||
$editor_limited = false;
|
||||
|
||||
$choice_id = 0;
|
||||
$count = 1;
|
||||
|
||||
/**
|
||||
* A filter that allows for the setting of the maximum number of choices shown in
|
||||
* the form editor for choice based fields (radio, checkbox, image, and multiple choice).
|
||||
*
|
||||
* @since 2.9
|
||||
*
|
||||
* @param int $max_choices_visible_count The default number of choices visible is 8.
|
||||
* @param object $field The current field object.
|
||||
*/
|
||||
$max_choices_count = gf_apply_filters( array( 'gform_field_choices_max_count_visible', $this->field->formId ), 8, $this->field );
|
||||
|
||||
$choices .= sprintf( '<div class="gfield_radio" id="%s">', esc_attr( $field_id ) );
|
||||
|
||||
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, $form );
|
||||
|
||||
if ( $is_form_editor && $count >= $max_choices_count ) {
|
||||
$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 ++;
|
||||
}
|
||||
}
|
||||
|
||||
$choices .= '</div>';
|
||||
|
||||
$total = sizeof( $field_choices );
|
||||
if ( $is_form_editor && ( $count < $total ) ) {
|
||||
$choices .= "<div class='gchoice_total'><span>" . sprintf( esc_html__( '%d of %d items shown. Edit choices to view all.', 'gravityforms' ), $count, $total ) . "</span></div>";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the HTML for multiple choices to be overridden.
|
||||
*
|
||||
* @since unknown
|
||||
*
|
||||
* @param string $choices The choices HTML.
|
||||
* @param object $field The current field object.
|
||||
*/
|
||||
return gf_apply_filters( array( 'gform_field_choices', $this->field->formId ), $choices, $this->field );
|
||||
}
|
||||
|
||||
public function get_choice_html( $choice, &$choice_id, $value, $disabled_text, $is_admin, $form = null ) {
|
||||
$form_id = absint( $this->field->formId );
|
||||
|
||||
if ( GFCommon::is_legacy_markup_enabled( $form_id ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( $is_admin || $form_id == 0 ) {
|
||||
$id = $this->field->id . '_' . $choice_id ++;
|
||||
} else {
|
||||
$id = $form_id . '_' . $this->field->id . '_' . $choice_id ++;
|
||||
}
|
||||
|
||||
$field_value = ! empty( $choice['value'] ) || $this->field->enableChoiceValue ? $choice['value'] : $choice['text'];
|
||||
|
||||
if ( $this->field->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->field, $choice, $value ) ? "checked='checked'" : '';
|
||||
}
|
||||
|
||||
$tabindex = $this->field->get_tabindex();
|
||||
|
||||
$image = $this->get_image_markup( $choice, $id, $choice_id, $form );
|
||||
$image_aria_describedby = 'gchoice_image_' . $id;
|
||||
|
||||
// Handle 'other' choice.
|
||||
$other = '';
|
||||
if ( $this->field->enableOtherChoice && rgar( $choice, 'isOtherChoice' ) ) {
|
||||
$input_disabled_text = $disabled_text;
|
||||
|
||||
if ( $value == 'gf_other_choice' && rgpost( "input_{$this->field->id}_other" ) ) {
|
||||
$other_value = rgpost( "input_{$this->field->id}_other" );
|
||||
} elseif ( ! empty( $value ) && ! GFFormsModel::choices_value_match( $this->field, $this->field->choices, $value ) ) {
|
||||
$other_value = $value;
|
||||
$value = 'gf_other_choice';
|
||||
$checked = "checked='checked'";
|
||||
} else {
|
||||
if ( ! $input_disabled_text ) {
|
||||
$input_disabled_text = "disabled='disabled'";
|
||||
}
|
||||
$other_value = empty( $choice['text'] ) ? GFCommon::get_other_choice_value( $this->field ) : $choice['text'];
|
||||
}
|
||||
|
||||
$other = "<br /><input id='input_{$this->field->formId}_{$this->field->id}_other' class='gchoice_other_control' name='input_{$this->field->id}_other' type='text' value='" . esc_attr( $other_value ) . "' aria-label='" . esc_attr__( 'Other Choice, please specify', 'gravityforms' ) . "' $tabindex $input_disabled_text />";
|
||||
}
|
||||
|
||||
// Handling of input/image aria-describedby
|
||||
$aria_describedby = '';
|
||||
if ( $this->add_aria_description( $checked, $choice_id ) ) {
|
||||
$image_aria_describedby = $image_aria_describedby ? array( $image_aria_describedby ) : array();
|
||||
$aria_describedby = $this->get_aria_describedby( $image_aria_describedby );
|
||||
} else if ( $image_aria_describedby ) {
|
||||
$aria_describedby = sprintf( 'aria-describedby="%s"', $image_aria_describedby );
|
||||
}
|
||||
|
||||
$choice_value = esc_attr( $field_value );
|
||||
|
||||
$choice_markup = "<div class='gchoice gchoice_{$id}'>
|
||||
<span class='gfield-image-choice-wrapper-outer'>
|
||||
{$image}
|
||||
<span class='gfield-image-choice-wrapper-inner'>
|
||||
<input class='gfield-choice-input' name='input_{$this->field->id}' type='radio' value='{$choice_value}' {$checked} id='choice_{$id}' onchange='gformToggleRadioOther( this )' {$tabindex} {$disabled_text} {$aria_describedby}/>
|
||||
<label for='choice_{$id}' id='label_{$id}' class='gform-field-label gform-field-label--type-inline'>
|
||||
{$choice['text']}
|
||||
</label>
|
||||
</span>
|
||||
{$other}
|
||||
</span>
|
||||
</div>";
|
||||
|
||||
/**
|
||||
* 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->field->formId, $this->field->id ), $choice_markup, $choice, $this->field, $value );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
class ChoiceDecorator {
|
||||
|
||||
/**
|
||||
* @var GF_Field
|
||||
*/
|
||||
protected $field;
|
||||
|
||||
public function __construct( $field ) {
|
||||
$this->field = $field;
|
||||
}
|
||||
|
||||
public function __call( $name, $args ) {
|
||||
return call_user_func_array( array( $this->field, $name ), $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the style classes for the image choice field.
|
||||
*
|
||||
* @since 2.9
|
||||
*
|
||||
* @param $form_id
|
||||
* @param $field_id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_field_classes( $form_id, $field ) {
|
||||
// Choice label visibility class
|
||||
$choice_label_visibility = GF_Field_Image_Choice::get_image_choice_label_visibility_setting( $field );
|
||||
$label_visibility_class = "ginput_container_image_choice--label-{$choice_label_visibility}";
|
||||
|
||||
// Choice input visibility class
|
||||
$choice_input_visibility = GF_Field_Image_Choice::get_image_choice_input_visibility_setting( $field );
|
||||
$input_visibility = ( $choice_input_visibility === 'show' ) && ( $choice_label_visibility === 'show' ) ? 'show' : 'hide';
|
||||
$input_visibility_class = "ginput_container_image_choice--input-{$input_visibility}";
|
||||
|
||||
return $label_visibility_class . ' ' . $input_visibility_class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the image markup for a choice field.
|
||||
*
|
||||
* @since 2.9
|
||||
*
|
||||
* @param $choice
|
||||
* @param $choice_id
|
||||
* @param $choice_number
|
||||
* @param $form
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_image_markup( $choice, $choice_id, $choice_number, $form ) {
|
||||
$image_aria_describedby = 'gchoice_image_' . $choice_id;
|
||||
|
||||
if ( ! empty( $choice['attachment_id'] ) ) {
|
||||
$image_alt = get_post_meta( $choice['attachment_id'], '_wp_attachment_image_alt', true );
|
||||
$image_alt = ! empty( $image_alt ) ? $image_alt : sprintf( '%s %d', __( 'Image for choice number', 'gravityforms' ), $choice_number );
|
||||
$image_size = isset( $form['styles'] ) && rgar( $form['styles'], 'inputImageChoiceSize' ) ? $form['styles']['inputImageChoiceSize'] : 'md';
|
||||
|
||||
$image = wp_get_attachment_image(
|
||||
$choice['attachment_id'],
|
||||
'gform-image-choice-' . $image_size,
|
||||
false,
|
||||
array(
|
||||
'class' => 'gfield-choice-image',
|
||||
'alt' => $image_alt,
|
||||
'id' => $image_aria_describedby,
|
||||
'loading' => 'false',
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$image = sprintf(
|
||||
'<span class="gfield-choice-image-no-image" id="%s"><span>%s</span></span>',
|
||||
$image_aria_describedby,
|
||||
sprintf(
|
||||
'%s %d %s',
|
||||
__( 'Choice number', 'gravityforms' ),
|
||||
$choice_number,
|
||||
__( 'does not have an image', 'gravityforms' )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return sprintf( '<div class="gfield-choice-image-wrapper">%s</div>', $image );
|
||||
}
|
||||
}
|
||||
|
||||
GFCommon::glob_require_once( '/includes/fields/field-decorator-choice/class-gf-field-decorator-choice-*.php' );
|
||||
@@ -131,6 +131,12 @@ class Block_Styles_Handler {
|
||||
/* Global CSS API: Control - File */
|
||||
'gf-ctrl-file-btn-bg-color-hover' => GFCommon::darken_color( $color_palette['inside-control']['color-darker'], 2 ),
|
||||
|
||||
/* Global CSS API: Field - Choice (Checkbox, Radio, Image, & Consent) */
|
||||
'gf-field-img-choice-size' => 'var(--gf-field-img-choice-size-' . $applied_settings['inputImageChoiceSize'] . ')',
|
||||
'gf-field-img-choice-card-space' => 'var(--gf-field-img-choice-card-space-' . $applied_settings['inputImageChoiceSize'] . ')',
|
||||
'gf-field-img-choice-check-ind-size' => 'var(--gf-field-img-choice-check-ind-size-' . $applied_settings['inputImageChoiceSize'] . ')',
|
||||
'gf-field-img-choice-check-ind-icon-size' => 'var(--gf-field-img-choice-check-ind-icon-size-' . $applied_settings['inputImageChoiceSize'] . ')',
|
||||
|
||||
/* Global CSS API: Field - Page */
|
||||
'gf-field-pg-steps-number-color' => 'rgba(' . implode( ', ', GFCommon::darken_color( $applied_settings['labelColor'], 0, 'rgb' ) ) . ', 0.8)',
|
||||
);
|
||||
@@ -144,7 +150,44 @@ class Block_Styles_Handler {
|
||||
}
|
||||
|
||||
public function styles( $form, $ajax, $settings, $block_settings ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$themes = \GFFormDisplay::get_themes_to_enqueue( $form );
|
||||
$styles = array( 'theme' => array() );
|
||||
|
||||
if ( in_array( 'orbital', $themes ) ) {
|
||||
$styles['theme'] = array( array( 'gravity_forms_orbital_theme' ) );
|
||||
$styles['foundation'] = array( array( 'gravity_forms_theme_foundation' ) );
|
||||
$styles['framework'] = array( array( 'gravity_forms_theme_framework' ) );
|
||||
$styles['reset'] = array( array( 'gravity_forms_theme_reset' ) );
|
||||
|
||||
if ( GFCommon::is_form_editor() ) {
|
||||
$styles['framework'][] = array( 'gravity_forms_theme_framework_admin' );
|
||||
$styles['foundation'][] = array( 'gravity_forms_theme_foundation_admin' );
|
||||
}
|
||||
}
|
||||
|
||||
if ( in_array( 'gravity-theme', $themes ) ) {
|
||||
|
||||
if ( GFCommon::is_entry_detail() ) {
|
||||
$styles['theme'][] = array( 'gform_theme_admin' );
|
||||
} else {
|
||||
$styles['theme'][] = array( 'gform_basic' );
|
||||
|
||||
/**
|
||||
* Allows users to disable the main theme.css file from being loaded on the Front End.
|
||||
*
|
||||
* @param boolean Whether to disable the theme css.
|
||||
* @since 2.5-beta-3
|
||||
*
|
||||
*/
|
||||
$disable_theme_css = apply_filters( 'gform_disable_form_theme_css', false );
|
||||
if ( ! $disable_theme_css ) {
|
||||
$styles['theme'][] = array( 'gform_theme' );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $styles;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
namespace Gravity_Forms\Gravity_Forms\Form_Display;
|
||||
|
||||
use Gravity_Forms\Gravity_Forms\Config\GF_Config_Service_Provider;
|
||||
use Gravity_Forms\Gravity_Forms\Form_Display\Config\GF_Product_Meta_Config;
|
||||
use Gravity_Forms\Gravity_Forms\Form_Display\Config\GF_Pagination_Config;
|
||||
use Gravity_Forms\Gravity_Forms\Form_Display\Full_Screen\Full_Screen_Handler;
|
||||
use Gravity_Forms\Gravity_Forms\Form_Display\Block_Styles\Block_Styles_Handler;
|
||||
use Gravity_Forms\Gravity_Forms\GF_Service_Container;
|
||||
@@ -25,6 +28,8 @@ class GF_Form_Display_Service_Provider extends GF_Service_Provider {
|
||||
const FULL_SCREEN_HANDLER = 'full_screen_handler';
|
||||
const BLOCK_STYLES_HANDLER = 'block_styles_handler';
|
||||
const BLOCK_STYLES_DEFAULTS = 'block_styles_defaults';
|
||||
const PRODUCT_META_CONFIG = 'products_meta_config';
|
||||
const PAGINATION_CONFIG = 'pagination_config';
|
||||
|
||||
/**
|
||||
* Register services to the container.
|
||||
@@ -38,6 +43,8 @@ class GF_Form_Display_Service_Provider extends GF_Service_Provider {
|
||||
require_once( plugin_dir_path( __FILE__ ) . '/block-styles/views/class-form-view.php' );
|
||||
require_once( plugin_dir_path( __FILE__ ) . '/block-styles/views/class-confirmation-view.php' );
|
||||
require_once( plugin_dir_path( __FILE__ ) . '/block-styles/block-styles-handler.php' );
|
||||
require_once( plugin_dir_path( __FILE__ ) . '/config/class-gf-product-meta-config.php' );
|
||||
require_once( plugin_dir_path( __FILE__ ) . '/config/class-gf-pagination-config.php' );
|
||||
|
||||
$container->add( self::FULL_SCREEN_HANDLER, function() use ( $container ) {
|
||||
// Use string handler for now to avoid JSON query issues on old platforms.
|
||||
@@ -63,6 +70,9 @@ class GF_Form_Display_Service_Provider extends GF_Service_Provider {
|
||||
// should be for the theme framework and CSS API. When empty, it defaults to:
|
||||
// buttonPrimaryBackgroundColor
|
||||
'inputPrimaryColor' => rgar( $form_styles, 'inputPrimaryColor' ) ? $form_styles['inputPrimaryColor'] : '', // #204ce5
|
||||
'inputImageChoiceAppearance' => rgar( $form_styles, 'inputImageChoiceAppearance' ) ? $form_styles['inputImageChoiceAppearance'] : 'card',
|
||||
'inputImageChoiceStyle' => rgar( $form_styles, 'inputImageChoiceStyle' ) ? $form_styles['inputImageChoiceStyle'] : 'square',
|
||||
'inputImageChoiceSize' => rgar( $form_styles, 'inputImageChoiceSize' ) ? $form_styles['inputImageChoiceSize'] : 'md',
|
||||
'labelFontSize' => rgar( $form_styles, 'labelFontSize' ) ? $form_styles['labelFontSize'] : 14,
|
||||
'labelColor' => rgar( $form_styles, 'labelColor' ) ? $form_styles['labelColor'] : '#112337',
|
||||
'descriptionFontSize' => rgar( $form_styles, 'descriptionFontSize' ) ? $form_styles['descriptionFontSize'] : 13,
|
||||
@@ -76,6 +86,19 @@ class GF_Form_Display_Service_Provider extends GF_Service_Provider {
|
||||
$container->add( self::BLOCK_STYLES_HANDLER, function() use ( $container ) {
|
||||
return new Block_Styles_Handler( $container->get( self::BLOCK_STYLES_DEFAULTS ) );
|
||||
});
|
||||
|
||||
// Product meta config.
|
||||
$container->add( self::PRODUCT_META_CONFIG, function () use ( $container ) {
|
||||
return new GF_Product_Meta_Config( $container->get( GF_Config_Service_Provider::DATA_PARSER ) );
|
||||
});
|
||||
$container->get( GF_Config_Service_Provider::CONFIG_COLLECTION )->add_config( $container->get( self::PRODUCT_META_CONFIG ) );
|
||||
|
||||
// Pagination config.
|
||||
$container->add( self::PAGINATION_CONFIG, function () use ( $container ) {
|
||||
return new GF_Pagination_Config( $container->get( GF_Config_Service_Provider::DATA_PARSER ) );
|
||||
});
|
||||
$container->get( GF_Config_Service_Provider::CONFIG_COLLECTION )->add_config( $container->get( self::PAGINATION_CONFIG ) );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,6 +121,7 @@ class GF_Form_Display_Service_Provider extends GF_Service_Provider {
|
||||
|
||||
add_action( 'gform_enqueue_scripts', array( $this, 'register_theme_styles' ) );
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'register_theme_styles' ) );
|
||||
add_action( 'enqueue_block_editor_assets', array( $this, 'register_theme_styles' ) );
|
||||
}
|
||||
|
||||
public function register_theme_styles() {
|
||||
@@ -114,9 +138,15 @@ class GF_Form_Display_Service_Provider extends GF_Service_Provider {
|
||||
*/
|
||||
$disable_css = apply_filters( 'gform_disable_css', get_option( 'rg_gforms_disable_css' ) );
|
||||
|
||||
if ( ! $disable_css ) {
|
||||
if ( GFCommon::is_form_editor() || GFCommon::is_block_editor_page() || ! $disable_css ) {
|
||||
wp_register_style( 'gravity_forms_theme_reset', "{$base_url}/assets/css/dist/gravity-forms-theme-reset{$dev_min}.css", array(), $version );
|
||||
wp_register_style( 'gravity_forms_theme_foundation', "{$base_url}/assets/css/dist/gravity-forms-theme-foundation{$dev_min}.css", array(), $version );
|
||||
wp_register_style(
|
||||
'gravity_forms_theme_foundation_admin',
|
||||
"{$base_url}/assets/css/dist/gravity-forms-theme-foundation-admin{$dev_min}.css",
|
||||
array( 'gravity_forms_theme_foundation' ),
|
||||
$version
|
||||
);
|
||||
wp_register_style(
|
||||
'gravity_forms_theme_framework',
|
||||
"{$base_url}/assets/css/dist/gravity-forms-theme-framework{$dev_min}.css",
|
||||
@@ -126,9 +156,14 @@ class GF_Form_Display_Service_Provider extends GF_Service_Provider {
|
||||
),
|
||||
$version
|
||||
);
|
||||
wp_register_style(
|
||||
'gravity_forms_theme_framework_admin',
|
||||
"{$base_url}/assets/css/dist/gravity-forms-theme-framework-admin{$dev_min}.css",
|
||||
array( 'gravity_forms_theme_framework' ),
|
||||
$version
|
||||
);
|
||||
wp_register_style( 'gravity_forms_orbital_theme', "{$base_url}/assets/css/dist/gravity-forms-orbital-theme{$dev_min}.css", array( 'gravity_forms_theme_framework' ), $version );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Forms\Form_Display\Config;
|
||||
|
||||
use Gravity_Forms\Gravity_Forms\Config\GF_Config;
|
||||
|
||||
/**
|
||||
* Form specific product meta config.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
class GF_Pagination_Config extends GF_Config {
|
||||
|
||||
protected $name = 'gform_theme_config';
|
||||
protected $script_to_localize = 'gform_gravityforms_theme';
|
||||
|
||||
/**
|
||||
* Config data.
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
public function data() {
|
||||
|
||||
if ( ! rgar( $this->args, 'form_ids' ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$pagination = array();
|
||||
foreach ( $this->args['form_ids'] as $form_id ) {
|
||||
$form = \GFFormDisplay::gform_pre_render( \GFAPI::get_form( $form_id ), 'form_config' );
|
||||
$pagination[ $form_id ] = rgar( $form, 'pagination' );
|
||||
}
|
||||
|
||||
return array(
|
||||
'common' => array(
|
||||
'form' => array(
|
||||
'pagination' => $pagination,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable ajax loading for the "gform_theme_config/common/form/pagination" config path.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param string $config_path The full path to the config item when stored in the browser's window object, for example: "gform_theme_config/common/form/product_meta"
|
||||
* @param array $args The args used to load the config data. This will be empty for generic config items. For form specific items will be in the format: array( 'form_ids' => array(123,222) ).
|
||||
*
|
||||
* @return bool Return true if the provided $config_path is the product_meta path. Return false otherwise.
|
||||
*/
|
||||
public function enable_ajax( $config_path, $args ) {
|
||||
if ( str_starts_with( $config_path, 'gform_theme_config/common/form/pagination' ) ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Forms\Form_Display\Config;
|
||||
|
||||
use Gravity_Forms\Gravity_Forms\Config\GF_Config;
|
||||
|
||||
/**
|
||||
* Form specific product meta config.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
class GF_Product_Meta_Config extends GF_Config {
|
||||
|
||||
protected $name = 'gform_theme_config';
|
||||
protected $script_to_localize = 'gform_gravityforms_theme';
|
||||
|
||||
/**
|
||||
* Config data.
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
public function data() {
|
||||
|
||||
if ( ! rgar( $this->args, 'form_ids' ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$product_metas = array();
|
||||
foreach ( $this->args['form_ids'] as $form_id ) {
|
||||
$product_metas[ $form_id ] = $this->get_product_meta( $form_id );
|
||||
}
|
||||
|
||||
return array(
|
||||
'common' => array(
|
||||
'form' => array(
|
||||
'product_meta' => $product_metas,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable ajax loading for the "gform_theme_config/common/form/product_meta" config path.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param string $config_path The full path to the config item when stored in the browser's window object, for example: "gform_theme_config/common/form/product_meta"
|
||||
* @param array $args The args used to load the config data. This will be empty for generic config items. For form specific items will be in the format: array( 'form_ids' => array(123,222) ).
|
||||
*
|
||||
* @return bool Return true if the provided $config_path is the product_meta path. Return false otherwise.
|
||||
*/
|
||||
public function enable_ajax( $config_path, $args ) {
|
||||
if ( str_starts_with( $config_path, 'gform_theme_config/common/form/product_meta' ) ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the product meta for a form.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param int $form_id The form ID.
|
||||
*
|
||||
* @return array|null Returns the product meta for the form. Returns null if the form does not contain any product fields.
|
||||
*/
|
||||
private function get_product_meta( $form_id ) {
|
||||
|
||||
$product_meta = array();
|
||||
$products = array();
|
||||
$form = \GFFormDisplay::gform_pre_render( \GFAPI::get_form( $form_id ), 'form_config' );
|
||||
$product_fields = \GFAPI::get_fields_by_type( $form, array( 'product' ) );
|
||||
if ( empty( $product_fields ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach ( $product_fields as $field ) {
|
||||
$products[ $field->id ] = $this->clean_meta( $field );
|
||||
|
||||
$options = array();
|
||||
$option_fields = \GFCommon::get_product_fields_by_type( $form, array( 'option' ), $field->id );
|
||||
if ( empty( $option_fields ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $option_fields as $option_field ) {
|
||||
$options[ $option_field->id ] = $this->clean_meta( $option_field );
|
||||
}
|
||||
|
||||
$products[ $field->id ]['options'] = $options;
|
||||
}
|
||||
|
||||
if ( !empty( $products ) ) {
|
||||
$product_meta['products'] = $products;
|
||||
}
|
||||
|
||||
$shipping_fields = \GFAPI::get_fields_by_type( $form, array( 'shipping' ) );
|
||||
if ( !empty( $shipping_fields ) ) {
|
||||
$product_meta['shipping'] = $this->clean_meta( $shipping_fields[0] );
|
||||
}
|
||||
|
||||
$product_meta['hash'] = self::hash( $product_meta );
|
||||
|
||||
return $product_meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans the field metadata so that it only contains a set of whitelisted properties.
|
||||
*
|
||||
* @param array $data Metadata to be cleaned.
|
||||
*
|
||||
* @return array Returns the clean metadata, only containing a set of whitelisted keys.
|
||||
* @since 2.9.0
|
||||
*
|
||||
*/
|
||||
private function clean_meta( $data )
|
||||
{
|
||||
$whitelisted = array( 'id', 'label', 'choices', 'inputs', 'type', 'inputType', 'basePrice', 'disableQuantity' );
|
||||
|
||||
// Convert to an associative array
|
||||
$data = (array) $data;
|
||||
|
||||
// Filter the array to only include whitelisted properties
|
||||
return array_intersect_key( $data, array_flip( $whitelisted ) );
|
||||
}
|
||||
}
|
||||
@@ -99,7 +99,6 @@ class Full_Screen_Handler {
|
||||
* @return string
|
||||
*/
|
||||
public function load_full_screen_template( $template ) {
|
||||
$form_for_display = $this->get_form_for_display();
|
||||
|
||||
/**
|
||||
* External filter usable by third-party code to modify/return the form ID for display. Useful for
|
||||
|
||||
@@ -314,7 +314,12 @@ class GF_Forms_Model_Legacy {
|
||||
* @param $lead_id
|
||||
* @deprecated
|
||||
* @see gform_delete_entry
|
||||
* @remove-in 3.0
|
||||
*/
|
||||
|
||||
if ( has_action( 'gform_delete_lead' ) ) {
|
||||
trigger_error( 'The gform_delete_lead action is deprecated and will be removed in version 3.0. Use gform_delete_entry instead.', E_USER_DEPRECATED );
|
||||
}
|
||||
do_action( 'gform_delete_lead', $lead_id );
|
||||
|
||||
$lead_table = self::get_lead_table_name();
|
||||
|
||||
@@ -1 +1 @@
|
||||
!function(a,o){var e;o(document).ready(function(){e=gflockingVars.objectType,a.init()}),a.init=function(){var n;n="gform-check-locked-objects-"+e,wp.heartbeat.interval(30),o(document).on("heartbeat-tick."+n,function(a,e){var c=e[n]||{};o(".gf-locking").each(function(a,e){var e=o(e),t=e.data("id");c.hasOwnProperty(t)?e.hasClass("wp-locked")||(t=c[t],e.find(".locked-text").text(t.text),e.find(".check-column input[type=checkbox]").prop("checked",!1),t.avatar_src&&(t=o('<img class="avatar avatar-18 photo" width="18" height="18" />').attr("src",t.avatar_src.replace(/&/g,"&")),e.find(".locked-avatar").empty().append(t)),e.addClass("wp-locked")):e.hasClass("wp-locked")&&e.removeClass("wp-locked").delay(1e3).find(".locked-info span").empty()})}).on("heartbeat-send."+n,function(a,e){var t=[];o(".gf-locking").each(function(a,e){t.push(o(e).data("id"))}),t.length&&(e[n]=t)})}}(window.gflocking=window.gflocking||{},jQuery);
|
||||
((a,o)=>{var e;o(document).ready(function(){e=gflockingVars.objectType,a.init()}),a.init=function(){var n;n="gform-check-locked-objects-"+e,wp.heartbeat.interval(30),o(document).on("heartbeat-tick."+n,function(a,e){var c=e[n]||{};o(".gf-locking").each(function(a,e){var e=o(e),t=e.data("id");c.hasOwnProperty(t)?e.hasClass("wp-locked")||(t=c[t],e.find(".locked-text").text(t.text),e.find(".check-column input[type=checkbox]").prop("checked",!1),t.avatar_src&&(t=o('<img class="avatar avatar-18 photo" width="18" height="18" />').attr("src",t.avatar_src.replace(/&/g,"&")),e.find(".locked-avatar").empty().append(t)),e.addClass("wp-locked")):e.hasClass("wp-locked")&&e.removeClass("wp-locked").delay(1e3).find(".locked-info span").empty()})}).on("heartbeat-send."+n,function(a,e){var t=[];o(".gf-locking").each(function(a,e){t.push(o(e).data("id"))}),t.length&&(e[n]=t)})}})(window.gflocking=window.gflocking||{},jQuery);
|
||||
@@ -1 +1 @@
|
||||
!function(t,e){var o,a;e(document).ready(function(){o=gflockingVars.objectID,a=gflockingVars.objectType,t.init()}),t.init=function(){var n;wp.heartbeat.interval(30),n="gform-check-locked-objects-"+a,e(document).on("heartbeat-tick."+n,function(t,a){var a=a[n]||{};a.hasOwnProperty(o)?(a=a[o],e(".locked-text").text(a.text),a.avatar_src&&(a=e('<img class="avatar avatar-18 photo" width="18" height="18" />').attr("src",a.avatar_src.replace(/&/g,"&")),e(".locked-avatar").empty().append(a))):e(".locked-info span").empty()}).on("heartbeat-send."+n,function(t,a){var e=[];e.push(o),a[n]=e})}}(window.gflocking=window.gflocking||{},jQuery);
|
||||
((t,e)=>{var o,a;e(document).ready(function(){o=gflockingVars.objectID,a=gflockingVars.objectType,t.init()}),t.init=function(){var n;wp.heartbeat.interval(30),n="gform-check-locked-objects-"+a,e(document).on("heartbeat-tick."+n,function(t,a){var a=a[n]||{};a.hasOwnProperty(o)?(a=a[o],e(".locked-text").text(a.text),a.avatar_src&&(a=e('<img class="avatar avatar-18 photo" width="18" height="18" />').attr("src",a.avatar_src.replace(/&/g,"&")),e(".locked-avatar").empty().append(a))):e(".locked-info span").empty()}).on("heartbeat-send."+n,function(t,a){var e=[];e.push(o),a[n]=e})}})(window.gflocking=window.gflocking||{},jQuery);
|
||||
@@ -1 +1 @@
|
||||
!function(t,s){s(document).ready(function(){t.init()});var a,e,i,n,r,l,u=!1;function g(){s("#gform-lock-request-status").html(gform.utils.escapeHtml(i.noResponse)),s("#gform-lock-request-button").attr("disabled",!1).text(i.requestAgain),l=!!(u=!1),wp.heartbeat.interval(30)}t.init=function(){var c,o;n=gflockingVars.hasLock,a=gflockingVars.objectID,e=gflockingVars.objectType,r=gflockingVars.lockUI,i=gflockingVars.strings,wp.heartbeat.interval(30),s("#wpwrap").append(r),c="gform-refresh-lock-"+e,o="gform-request-lock-"+e,s(document).on("heartbeat-send."+c,function(t,e){var r={};a&&s("#gform-lock-dialog").length&&0!=n&&(r.objectID=a,e[c]=r)}),s(document).on("heartbeat-send."+o,function(t,e){var r={};if(!u)return e;r.objectID=a,e[o]=r}),s(document).on("heartbeat-tick."+c,function(t,e){var r,o,a;e[c]&&((e=e[c]).lock_error||e.lock_request)&&(a=e.lock_error||e.lock_request,(r=s("#gform-lock-dialog")).length)&&(r.is(":visible")?e.lock_error?s("#gform-reject-lock-request-button").is(":visible")&&(e.lock_error.avatar_src&&(o=s('<img class="avatar avatar-64 photo" width="64" height="64" />').attr("src",e.lock_error.avatar_src.replace(/&/g,"&")),r.find("div.gform-locked-avatar").empty().append(o)),s("#gform-reject-lock-request-button").hide(),r.show().find(".currently-editing").text(e.lock_error.text)):e.lock_request&&s("#gform-lock-request-status").html(gform.utils.escapeScripts(e.lock_request.text)):(a.avatar_src&&(o=s('<img class="avatar avatar-64 photo" width="64" height="64" />').attr("src",a.avatar_src.replace(/&/g,"&")),r.find("div.gform-locked-avatar").empty().append(o)),r.show().find(".currently-editing").text(a.text),e.lock_request?s("#gform-reject-lock-request-button").show():s("#gform-reject-lock-request-button").hide(),r.find(".wp-tab-first").focus()))}),s(document).on("heartbeat-tick."+o,function(t,e){if(e[o]&&(e=e[o]).status&&(e=e.status,s("#gform-lock-dialog").length))switch("pending"!=e&&(clearTimeout(l),u=l=!1),e){case"granted":s("#gform-lock-request-status").html(i.gainedControl),s("#gform-take-over-button").show(),s("#gform-lock-request-button").hide(),n=!0;break;case"deleted":s("#gform-lock-request-button").text(i.requestAgain).attr("disabled",!1),s("#gform-lock-request-status").html(i.rejected);break;case"pending":s("#gform-lock-request-status").html(i.pending)}}),s("#gform-lock-request-button").click(function(){var t=s(this);t.text("Request sent"),t.attr("disabled",!0),s("#gform-lock-request-status").html(""),u=!!1,wp.heartbeat.interval(5),l=setTimeout(g,12e4),s.getJSON(ajaxurl,{action:"gf_lock_request_"+e,object_id:a}).done(function(t){s("#gform-lock-request-status").html(gform.utils.escapeScripts(t.html))}).fail(function(t,e,r){e=e+", "+r;s("#gform-lock-request-status").html(gform.utils.escapeScripts(i.requestError+": "+e))})}),s("#gform-reject-lock-request-button").click(function(){s.getJSON(ajaxurl,{action:"gf_reject_lock_request_"+e,object_id:a,object_type:e}).done(function(t){s("#gform-lock-dialog").hide()}).fail(function(t,e,r){e=e+", "+r;s("#gform-lock-request-status").html(gform.utils.escapeScripts(i.requestError+": "+e)),s("#gform-lock-dialog").hide()})})}}(window.gflocking=window.gflocking||{},jQuery);
|
||||
((t,s)=>{s(document).ready(function(){t.init()});var a,e,i,n,r,l,u=!1;function g(){s("#gform-lock-request-status").html(gform.utils.escapeHtml(i.noResponse)),s("#gform-lock-request-button").attr("disabled",!1).text(i.requestAgain),l=!!(u=!1),wp.heartbeat.interval(30)}t.init=function(){var c,o;n=gflockingVars.hasLock,a=gflockingVars.objectID,e=gflockingVars.objectType,r=gflockingVars.lockUI,i=gflockingVars.strings,wp.heartbeat.interval(30),s("#wpwrap").append(r),c="gform-refresh-lock-"+e,o="gform-request-lock-"+e,s(document).on("heartbeat-send."+c,function(t,e){var r={};a&&s("#gform-lock-dialog").length&&0!=n&&(r.objectID=a,e[c]=r)}),s(document).on("heartbeat-send."+o,function(t,e){var r={};if(!u)return e;r.objectID=a,e[o]=r}),s(document).on("heartbeat-tick."+c,function(t,e){var r,o,a;e[c]&&((e=e[c]).lock_error||e.lock_request)&&(a=e.lock_error||e.lock_request,(r=s("#gform-lock-dialog")).length)&&(r.is(":visible")?e.lock_error?s("#gform-reject-lock-request-button").is(":visible")&&(e.lock_error.avatar_src&&(o=s('<img class="avatar avatar-64 photo" width="64" height="64" />').attr("src",e.lock_error.avatar_src.replace(/&/g,"&")),r.find("div.gform-locked-avatar").empty().append(o)),s("#gform-reject-lock-request-button").hide(),r.show().find(".currently-editing").text(e.lock_error.text)):e.lock_request&&s("#gform-lock-request-status").html(gform.utils.escapeScripts(e.lock_request.text)):(a.avatar_src&&(o=s('<img class="avatar avatar-64 photo" width="64" height="64" />').attr("src",a.avatar_src.replace(/&/g,"&")),r.find("div.gform-locked-avatar").empty().append(o)),r.show().find(".currently-editing").text(a.text),e.lock_request?s("#gform-reject-lock-request-button").show():s("#gform-reject-lock-request-button").hide(),r.find(".wp-tab-first").focus()))}),s(document).on("heartbeat-tick."+o,function(t,e){if(e[o]&&(e=e[o]).status&&(e=e.status,s("#gform-lock-dialog").length))switch("pending"!=e&&(clearTimeout(l),u=l=!1),e){case"granted":s("#gform-lock-request-status").html(i.gainedControl),s("#gform-take-over-button").show(),s("#gform-lock-request-button").hide(),n=!0;break;case"deleted":s("#gform-lock-request-button").text(i.requestAgain).attr("disabled",!1),s("#gform-lock-request-status").html(i.rejected);break;case"pending":s("#gform-lock-request-status").html(i.pending)}}),s("#gform-lock-request-button").click(function(){var t=s(this);t.text("Request sent"),t.attr("disabled",!0),s("#gform-lock-request-status").html(""),u=!!1,wp.heartbeat.interval(5),l=setTimeout(g,12e4),s.getJSON(ajaxurl,{action:"gf_lock_request_"+e,object_id:a}).done(function(t){s("#gform-lock-request-status").html(gform.utils.escapeScripts(t.html))}).fail(function(t,e,r){e=e+", "+r;s("#gform-lock-request-status").html(gform.utils.escapeScripts(i.requestError+": "+e))})}),s("#gform-reject-lock-request-button").click(function(){s.getJSON(ajaxurl,{action:"gf_reject_lock_request_"+e,object_id:a,object_type:e}).done(function(t){s("#gform-lock-dialog").hide()}).fail(function(t,e,r){e=e+", "+r;s("#gform-lock-request-status").html(gform.utils.escapeScripts(i.requestError+": "+e)),s("#gform-lock-dialog").hide()})})}})(window.gflocking=window.gflocking||{},jQuery);
|
||||
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
/**
|
||||
* Handles logic for encrypting / decrypting settings.
|
||||
*
|
||||
* @package Gravity_Forms\Gravity_Forms\Honeypot
|
||||
*/
|
||||
|
||||
namespace Gravity_Forms\Gravity_Forms\Settings;
|
||||
|
||||
/**
|
||||
* Class GF_Settings_Encryption
|
||||
*
|
||||
* @since 2.7.17
|
||||
*
|
||||
* Provides functionality for handling the encryption and decryption of settings
|
||||
*/
|
||||
class GF_Settings_Encryption {
|
||||
|
||||
/**
|
||||
* The encryption key to use for encrypting / decrypting settings.
|
||||
*
|
||||
* @since 2.7.17
|
||||
*
|
||||
* @var string The encryption key to use for encrypting / decrypting settings.
|
||||
*/
|
||||
private $_encryption_key;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 2.7.17
|
||||
*
|
||||
* @param string $encryption_key Encryption key to use for encrypting / decrypting settings. Defaults to GF_ENCRYPTION_KEY constant.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function __construct( $encryption_key = '' ) {
|
||||
if ( ! empty( $encryption_key ) ) {
|
||||
$this->_encryption_key = $encryption_key;
|
||||
} else {
|
||||
$this->_encryption_key = defined( 'GF_ENCRYPTION_KEY' ) ? GF_ENCRYPTION_KEY : '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if settings encryption is enabled.
|
||||
*
|
||||
* @since 2.7.17
|
||||
*
|
||||
* @return bool True if settings encryption is enabled. False otherwise.
|
||||
*
|
||||
*/
|
||||
public function is_enabled() {
|
||||
return ! empty( $this->get_key() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the GF_ENCRYPTION_KEY constant for the settings page.
|
||||
*
|
||||
* @since 2.7.17
|
||||
*
|
||||
* @return string The value of the GF_ENCRYPTION_KEY constant.
|
||||
*/
|
||||
public function get_key() {
|
||||
return $this->_encryption_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will encrypt a settings array given it has encryption enabled, is not an empty array, and is not currently encrypted.
|
||||
*
|
||||
* @since 2.7.17
|
||||
*
|
||||
* @param array $settings An array of settings values
|
||||
*
|
||||
* @return false|mixed|string Will return a json block containing the encrypted setting values, otherwise returns original setting values.
|
||||
*/
|
||||
public function encrypt( $settings ) {
|
||||
if ( ! $this->is_enabled() ) {
|
||||
return $settings;
|
||||
}
|
||||
|
||||
$settings_wrapper = $this->get_wrapper( $settings );
|
||||
if ( ! empty( $settings_wrapper ) && ! rgar( $settings_wrapper, 'encrypted' ) ) {
|
||||
$key = $this->get_key();
|
||||
$settings = json_encode(
|
||||
array(
|
||||
'encrypted' => true,
|
||||
'value' => \GFCommon::openssl_encrypt( json_encode( $settings_wrapper ), $key, 'aes-256-ctr', $key ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will decrypt settings given it has encryption enabled and is currently encrypted.
|
||||
*
|
||||
* @since 2.7.17
|
||||
*
|
||||
* @param $settings
|
||||
*
|
||||
* @return mixed Will return the decrypted settings values, otherwise returns original settings values.
|
||||
*/
|
||||
public function decrypt( $settings ) {
|
||||
if ( ! $this->is_enabled() ) {
|
||||
return $settings;
|
||||
}
|
||||
|
||||
$settings = $this->get_wrapper( $settings );
|
||||
if ( rgar( $settings, 'encrypted' ) ) {
|
||||
$key = $this->get_key();
|
||||
$settings = json_decode( \GFCommon::openssl_decrypt( rgar( $settings, 'value' ), $key, 'aes-256-ctr', $key ), true );
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* For encrypted settings, returns the decoded JSON wrapper.
|
||||
*
|
||||
* @since 2.7.17
|
||||
*
|
||||
* @param string $setting a settings value
|
||||
*
|
||||
* @return bool returns the decoded JSON wrapper for encrypted settings, otherwise returns the original settings.
|
||||
*/
|
||||
public function get_wrapper( $setting ) {
|
||||
if ( empty( $setting ) || ! is_string( $setting ) ) {
|
||||
return $setting;
|
||||
}
|
||||
|
||||
$wrapper = json_decode( $setting, true );
|
||||
if ( ! rgar( $wrapper, 'encrypted' ) ) {
|
||||
return $setting;
|
||||
}
|
||||
|
||||
return $wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* When encryption is enabled, will decrypt all fields that are encrypted and return the resulting array.
|
||||
*
|
||||
* @since 2.7.17
|
||||
*
|
||||
* @param $meta array The feed meta array.
|
||||
*
|
||||
* @return array Returns the feed meta array with all fields decrypted.
|
||||
*/
|
||||
public function decrypt_feed_meta( $meta ) {
|
||||
|
||||
if ( ! $this->is_enabled() || ! is_array( $meta ) ) {
|
||||
return $meta;
|
||||
}
|
||||
|
||||
foreach ( $meta as $name => $value ) {
|
||||
if ( ! empty( $value ) ) {
|
||||
$meta[ $name ] = $this->decrypt( $value );
|
||||
}
|
||||
}
|
||||
|
||||
return $meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* When encryption is enabled, will encrypt all fields marked for encryption and return the resulting array.
|
||||
*
|
||||
* @since 2.7.17
|
||||
*
|
||||
* @param $meta array The feed meta array.
|
||||
* @param $fields_to_encrypt array The array of field names to encrypt.
|
||||
*
|
||||
* @return array Returns the feed meta array with all fields marked for encryption encrypted.
|
||||
*/
|
||||
public function encrypt_feed_meta( $meta, $fields_to_encrypt = array() ) {
|
||||
|
||||
if ( ! $this->is_enabled() || ! is_array( $meta ) ) {
|
||||
return $meta;
|
||||
}
|
||||
|
||||
foreach ( $meta as $name => $value ) {
|
||||
if ( ! empty( $value ) && in_array( $name, $fields_to_encrypt ) ) {
|
||||
$meta[ $name ] = $this->encrypt( $value );
|
||||
}
|
||||
}
|
||||
|
||||
return $meta;
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,9 @@ class GF_Settings_Service_Provider extends GF_Service_Provider {
|
||||
const SETTINGS_CONFIG_I18N = 'settings_config_i18n';
|
||||
const SETTINGS_CONFIG_ADMIN = 'settings_config_admin';
|
||||
|
||||
// Encryption utils
|
||||
const SETTINGS_ENCRYPTION = 'settings_encryption';
|
||||
|
||||
/**
|
||||
* Array mapping config class names to their container ID.
|
||||
*
|
||||
@@ -42,6 +45,14 @@ class GF_Settings_Service_Provider extends GF_Service_Provider {
|
||||
* @param GF_Service_Container $container
|
||||
*/
|
||||
public function register( GF_Service_Container $container ) {
|
||||
|
||||
// Encryption utils
|
||||
require_once( plugin_dir_path( __FILE__ ) . '/class-gf-settings-encryption.php' );
|
||||
$container->add( self::SETTINGS_ENCRYPTION, function () {
|
||||
return new GF_Settings_Encryption();
|
||||
} );
|
||||
|
||||
|
||||
// Configs
|
||||
require_once( plugin_dir_path( __FILE__ ) . '/config/class-gf-settings-config-i18n.php' );
|
||||
require_once( plugin_dir_path( __FILE__ ) . '/config/class-gf-settings-config-admin.php' );
|
||||
@@ -68,4 +79,4 @@ class GF_Settings_Service_Provider extends GF_Service_Provider {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1677,7 +1677,6 @@ class Settings {
|
||||
} else if ( is_string( $callback ) ) {
|
||||
update_option( $callback, $values );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -2641,6 +2640,7 @@ class Settings {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save previous field values.
|
||||
*
|
||||
@@ -2717,10 +2717,6 @@ class Settings {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// # MISC HELPER METHODS -------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -2735,5 +2731,4 @@ class Settings {
|
||||
return ! rgempty( 'gform-settings-save' );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -125,6 +125,14 @@ class Base implements ArrayAccess {
|
||||
*/
|
||||
public $settings;
|
||||
|
||||
/** Used to check if encryption is suppported.
|
||||
*
|
||||
* @since 2.7.15.2
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $encrypt;
|
||||
|
||||
/**
|
||||
* Field id.
|
||||
*
|
||||
|
||||
@@ -47,11 +47,11 @@ class GF_Splash_Page {
|
||||
* @param Splash_Page_Template_Tags\GF_Splash_Page_Template_Tags $tags
|
||||
*/
|
||||
public function __construct( $tags ) {
|
||||
$this->about_version = '2.8';
|
||||
$this->about_version = '2.9';
|
||||
|
||||
$this->tags = $tags;
|
||||
|
||||
$this->img_dir = 'https://cdn.gravity.com/gravityforms/about-page/2.8/';
|
||||
$this->img_dir = 'https://cdn.gravity.com/gravityforms/about-page/2.9/';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,83 +1,144 @@
|
||||
<article class="gform-splash" data-js="gform-splash-page">
|
||||
|
||||
<header class="gform-splash__header">
|
||||
<img class="gform-logo" src="<?php echo esc_url( GFCommon::get_base_url() ); ?>/images/logos/gravity-logo-white.svg" alt="Gravity Forms"/>
|
||||
<h1><?php esc_html_e( 'Edit Forms with Ease in Gravity Forms 2.8!', 'gravityforms' ); ?></h1>
|
||||
<p><?php esc_html_e( 'The new Compact View makes it a cinch to edit long forms!', 'gravityforms' ); ?></p>
|
||||
<h1><?php esc_html_e( 'New Fields Added in Gravity Forms 2.9!', 'gravityforms' ); ?></h1>
|
||||
<p><?php esc_html_e( 'The new Image Choice and Multiple Choice fields give you more flexibility and control when creating forms.', 'gravityforms' ); ?></p>
|
||||
<a class="gform-button gform-button--size-height-xxl gform-button--white gform-button--width-auto gform-button--icon-trailing" href="<?php echo esc_url( admin_url( 'admin.php?page=gf_new_form' ) ); ?>" title="<?php esc_attr_e( 'Get started with a new form', 'gravityforms' ); ?>">
|
||||
<span class="gform-button__text gform-button__text--inactive gform-typography--size-text-md"><?php esc_html_e( 'Get Started', 'gravityforms' ); ?></span>
|
||||
<span class="gform-common-icon gform-common-icon--arrow-narrow-right gform-button__icon"></span>
|
||||
</a>
|
||||
<div class="gform-reviews">
|
||||
<a href="https://www.g2.com/products/gravity-forms/reviews" title="<?php esc_html_e( 'Read reviews of Gravity Forms on G2', 'gravityforms' ); ?>">
|
||||
<img src="<?php echo $this->img_dir . 'g2.svg'; ?>" alt="<?php esc_attr_e( 'G2 logo', 'gravityforms' ); ?>">
|
||||
<span class="gform-reviews__stars">
|
||||
<span class="gform-common-icon gform-common-icon--star"></span>
|
||||
<span class="gform-common-icon gform-common-icon--star"></span>
|
||||
<span class="gform-common-icon gform-common-icon--star"></span>
|
||||
<span class="gform-common-icon gform-common-icon--star"></span>
|
||||
<span class="gform-common-icon gform-common-icon--star"></span>
|
||||
</span>
|
||||
200+ <?php esc_html_e( '4.7 Stars', 'gravityforms' ); ?>
|
||||
</a>
|
||||
<ul class="gform-reviews__list">
|
||||
<li class="gform-reviews__list-item gform-reviews__list-item--g2">
|
||||
<a
|
||||
href="https://www.g2.com/products/gravity-forms/reviews"
|
||||
title="<?php esc_html_e( 'Read reviews of Gravity Forms on G2', 'gravityforms' ); ?>"
|
||||
target="_blank"
|
||||
class="gform-reviews__link"
|
||||
>
|
||||
<img
|
||||
src="<?php echo $this->img_dir . 'g2.svg'; ?>"
|
||||
alt="<?php esc_attr_e( 'G2 logo', 'gravityforms' ); ?>"
|
||||
class="gform-reviews__logo"
|
||||
/>
|
||||
<span class="gform-reviews__stars gform-reviews__stars--icon">
|
||||
<span class="gform-common-icon gform-common-icon--star"></span>
|
||||
<span class="gform-common-icon gform-common-icon--star"></span>
|
||||
<span class="gform-common-icon gform-common-icon--star"></span>
|
||||
<span class="gform-common-icon gform-common-icon--star"></span>
|
||||
<span class="gform-common-icon gform-common-icon--star"></span>
|
||||
</span>
|
||||
200+ <?php esc_html_e( '4.7 Stars', 'gravityforms' ); ?>
|
||||
</a>
|
||||
</li>
|
||||
<li class="gform-reviews__list-item gform-reviews__list-item--trustpilot">
|
||||
<a
|
||||
href="https://www.trustpilot.com/review/gravityforms.com"
|
||||
title="<?php esc_html_e( 'Read reviews of Gravity Forms on Trustpilot', 'gravityforms' ); ?>"
|
||||
class="gform-reviews__link"
|
||||
target="_blank"
|
||||
>
|
||||
<img
|
||||
src="<?php echo $this->img_dir . 'trustpilot.svg'; ?>"
|
||||
alt="<?php esc_attr_e( 'Trustpilot logo', 'gravityforms' ); ?>"
|
||||
class="gform-reviews__logo"
|
||||
/>
|
||||
<span class="gform-reviews__stars gform-reviews__stars--image">
|
||||
<img
|
||||
src="<?php echo $this->img_dir . 'trustpilot-rating.svg'; ?>"
|
||||
alt="<?php esc_attr_e( 'Trustpilot rating', 'gravityforms' ); ?>"
|
||||
class="gform-reviews__stars-image"
|
||||
/>
|
||||
</span>
|
||||
50+ <?php esc_html_e( '4.4 Stars', 'gravityforms' ); ?>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="gform-splash__body">
|
||||
<?php
|
||||
$text = '<h3>' . __( 'Form Editor Compact View', 'gravityforms' ) . '</h3>
|
||||
<p>' . __( 'Our new compact view makes it easier than ever to edit your forms! If you have long forms, you no longer have to scroll for ages to find the field you’re looking for. The compact view gives you a bird’s eye view of your form, so you can quickly find the fields you need to edit.', 'gravityforms' ) . ' <a href="https://docs.gravityforms.com/compact-view/" title="' . __( 'Read more about Compact View', 'gravityforms' ) . '" target="_blank">' . __( 'Read More', 'gravityforms' ) . '</a></p>';
|
||||
$image = array(
|
||||
'src' => $this->img_dir . 'compact-view.png',
|
||||
'alt' => __( 'Screenshot of the compact view in Gravity Forms 2.8', 'gravityforms' ),
|
||||
);
|
||||
|
||||
echo wp_kses_post(
|
||||
$this->tags->equal_columns(
|
||||
array(
|
||||
'columns' => array(
|
||||
$this->tags->build_image_html( $image ),
|
||||
$text,
|
||||
),
|
||||
'container_classes' => 'column--vertical-center',
|
||||
),
|
||||
)
|
||||
);
|
||||
<div class="gform-splash__sections">
|
||||
<?php
|
||||
$text = '<h3>' . __( 'Image Choice Field', 'gravityforms' ) . '</h3>
|
||||
<p>' . __( 'A picture is worth a thousand words! The new Image Choice field lets you add stylish images straight from the media library to your choices. Easily create beautiful forms with eye-catching images that speak to your users.', 'gravityforms' ) . '</p>
|
||||
<a href="https://docs.gravityforms.com/image-choice-field/" target="_blank" class="gform-button gform-button--size-height-xl gform-button--primary-new gform-button--width-auto" aria-label="' . __( 'Read more about the Image Choice field', 'gravityforms' ) . '" title="' . __( 'Read more about the Image Choice field', 'gravityforms' ) . '"><span class="gform-button__text gform-button__text--inactive gform-typography--size-text-sm">' . __( 'Read More', 'gravityforms' ) . '</span></a>';
|
||||
$image = array(
|
||||
'src' => $this->img_dir . 'image-choice-field.png',
|
||||
'alt' => __( 'Screenshot of the Image Choice field in Gravity Forms 2.9', 'gravityforms' ),
|
||||
);
|
||||
|
||||
$style_icon = $this->tags->build_image_html(
|
||||
array(
|
||||
'src' => $this->img_dir . 'icon-swatch.png',
|
||||
'alt' => __( 'Icon of color swatches', 'gravityforms' ),
|
||||
'width' => '48px',
|
||||
'height' => '48px',
|
||||
'class' => 'image--width-auto',
|
||||
)
|
||||
);
|
||||
$db_icon = $this->tags->build_image_html(
|
||||
array(
|
||||
'src' => $this->img_dir . 'icon-db.png',
|
||||
'alt' => __( 'Icon of a database', 'gravityforms' ),
|
||||
'width' => '48px',
|
||||
'height' => '48px',
|
||||
'class' => 'image--width-auto',
|
||||
)
|
||||
);
|
||||
$col1text = $style_icon . '<h4>' . __( 'Orbital Form Styling', 'gravityforms' ) . '</h4>
|
||||
<p>' . __( 'You might have noticed that we recently added a new setting so that you can use the beautiful and customizable Orbital form theme everywhere on your site, including shortcodes! Soon you’ll see Orbital in more places, and you’ll find more ways to customize it.', 'gravityforms' ) . ' <a href="https://docs.gravityforms.com/block-themes-and-style-settings/" title="' . __( 'Read more about styling your forms', 'gravityforms' ) . '" target="_blank">' . __( 'Read More', 'gravityforms' ) . '</a></p>';
|
||||
$col2text = $db_icon . '<h4>' . __( 'Performance Improvements', 'gravityforms' ) . '</h4>
|
||||
<p>' . __( 'We are always striving to improve the performance of Gravity Forms. In this release, you’ll notice smaller CSS files so that you don’t have to sacrifice performance to have good-looking forms.', 'gravityforms' ) . '</p>';
|
||||
echo wp_kses_post(
|
||||
$this->tags->equal_columns(
|
||||
array(
|
||||
'columns' => array(
|
||||
$col1text,
|
||||
$col2text,
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
echo wp_kses_post(
|
||||
$this->tags->equal_columns(
|
||||
array(
|
||||
'columns' => array(
|
||||
$this->tags->build_image_html( $image ),
|
||||
$text,
|
||||
),
|
||||
'container_classes' => 'column--vertical-center',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
?>
|
||||
$text = '<h3>' . __( 'Multiple Choice Field', 'gravityforms' ) . '</h3>
|
||||
<p>' . __( 'The Multiple Choice field is a new, flexible way to let users choose one or many options. Gather the information you need, while ensuring a high-end experience for those submitting the form.', 'gravityforms' ) . '</p>
|
||||
<a href="https://docs.gravityforms.com/multiple-choice-field/" target="_blank" class="gform-button gform-button--size-height-xl gform-button--primary-new gform-button--width-auto" aria-label="' . __( 'Read more about the Multiple Choice field', 'gravityforms' ) . '" title="' . __( 'Read more about the Multiple Choice field', 'gravityforms' ) . '"><span class="gform-button__text gform-button__text--inactive gform-typography--size-text-sm">' . __( 'Read More', 'gravityforms' ) . '</span></a>';
|
||||
$image = array(
|
||||
'src' => $this->img_dir . 'multiple-choice-field.png',
|
||||
'alt' => __( 'Screenshot of the Multiple Choice field in Gravity Forms 2.9', 'gravityforms' ),
|
||||
);
|
||||
|
||||
echo wp_kses_post(
|
||||
$this->tags->equal_columns(
|
||||
array(
|
||||
'columns' => array(
|
||||
$text,
|
||||
$this->tags->build_image_html( $image ),
|
||||
),
|
||||
'container_classes' => 'column--vertical-center',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$col1_icon = $style_icon = $this->tags->build_image_html(
|
||||
array(
|
||||
'src' => $this->img_dir . 'editor-design-improvements-icon.svg',
|
||||
'alt' => __( 'Icon of color swatches', 'gravityforms' ),
|
||||
'width' => '52px',
|
||||
'height' => '52px',
|
||||
'class' => 'image--width-auto',
|
||||
)
|
||||
);
|
||||
$col1 = $col1_icon . '<h4>' . __( 'Editor Design Improvements', 'gravityforms' ) . '</h4>
|
||||
<p>' . __( 'We’ve brought our beautiful Orbital form theme into the form editor! With 2.9 you’ll find a more consistent and visually-pleasing form editing experience, closely mirroring how your form will look on the front end.', 'gravityforms' ) . ' <a href="https://docs.gravityforms.com/gravity-forms-2-9-key-features/" title="' . __( 'Read more about the Gravity Forms 2.9 editor design improvements', 'gravityforms' ) . '" target="_blank">' . __( 'Read More', 'gravityforms' ) . '</a></p>';
|
||||
|
||||
$col2_icon = $style_icon = $this->tags->build_image_html(
|
||||
array(
|
||||
'src' => $this->img_dir . 'editor-accessibility-improvements-icon.svg',
|
||||
'alt' => __( 'Icon of accessibility symbol', 'gravityforms' ),
|
||||
'width' => '52px',
|
||||
'height' => '52px',
|
||||
'class' => 'image--width-auto',
|
||||
)
|
||||
);
|
||||
$col2 = $col2_icon . '<h4>' . __( 'Editor Accessibility Improvements', 'gravityforms' ) . '</h4>
|
||||
<p>' . __( 'As part of our continuing commitment to make form building available to everyone, we have improved the accessibility of the form editor. If you rely on keyboard navigation or screen readers, you’ll now have an easier time navigating the field settings.', 'gravityforms' ) . ' <a href="https://docs.gravityforms.com/gravity-forms-2-9-key-features/" title="' . __( 'Read more about the Gravity Forms 2.9 editor accessibility improvements', 'gravityforms' ) . '" target="_blank">' . __( 'Read More', 'gravityforms' ) . '</a></p>';
|
||||
|
||||
echo wp_kses_post(
|
||||
$this->tags->equal_columns(
|
||||
array(
|
||||
'columns' => array(
|
||||
$col1,
|
||||
$col2,
|
||||
),
|
||||
'container_classes' => 'column--vertical-center',
|
||||
),
|
||||
)
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
|
||||
<footer class="gform-splash__footer">
|
||||
<h4>
|
||||
|
||||
@@ -34,6 +34,28 @@ class Asset_Enqueue_Output_Engine extends Output_Engine {
|
||||
$this->styles = $styles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Array of no conflict styles.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @var array Array of style to be added to the no conflict style list.
|
||||
*/
|
||||
private $_no_conflict_styles = array();
|
||||
|
||||
/**
|
||||
* Adds a style handle to the list of no conflict styles.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param string $handle Style to be added to the no conflict list.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_no_conflict_style( $handle ) {
|
||||
$this->_no_conflict_styles[] = $handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for scripts.
|
||||
*
|
||||
@@ -55,48 +77,122 @@ class Asset_Enqueue_Output_Engine extends Output_Engine {
|
||||
public function output() {
|
||||
$self = $this;
|
||||
|
||||
// Enqueue scripts and styles for blocks.
|
||||
add_action( 'gform_post_enqueue_scripts', function ( $found_forms, $found_blocks, $post ) use ( $self ) {
|
||||
foreach ( $found_blocks as $block ) {
|
||||
$settings = $self->get_settings( $block['attrs']['formId'] );
|
||||
$form = \GFFormsModel::get_form( $block['attrs']['formId'] );
|
||||
$styles = call_user_func_array( $self->styles, array( $form, false, $settings, $block['attrs'] ) );
|
||||
$scripts = call_user_func_array( $self->scripts, array( $form, false, $settings, $block['attrs'] ) );
|
||||
// Don't enqueue assets if we're doing an AJAX request.
|
||||
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->process_form_assets( $styles, $scripts );
|
||||
// Enqueue styles for admin pages other than the form editor and block editor.
|
||||
add_action( 'admin_enqueue_scripts', function() use ( $self ) {
|
||||
|
||||
// Ignore block editor pages because they are handled separately below.
|
||||
if ( \GFCommon::is_block_editor_page() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
}, 999, 3 );
|
||||
// Handle pages where there is a form context.
|
||||
$form = $settings = array();
|
||||
if ( in_array( \GFForms::get_page(), array( 'form_editor', 'entry_detail', 'entry_detail_edit' ) ) ) {
|
||||
$form = GFAPI::get_form( rgget( 'id' ) );
|
||||
$settings = $self->get_settings( $form['id'] );
|
||||
}
|
||||
|
||||
// Enqueue scripts and styles for forms that aren't in blocks.
|
||||
add_action( 'gform_enqueue_scripts', function ( $form, $ajax ) use ( $self ) {
|
||||
$page_instance = isset( $form['page_instance'] ) ? $form['page_instance'] : - 1;
|
||||
$settings = $this->get_settings( $form['id'] );
|
||||
$block_settings = $this->get_block_settings( $form['id'], $page_instance );
|
||||
$self->enqueue_form_styles( $form, $settings );
|
||||
}, 1000 );
|
||||
|
||||
// Get the settings from the shortcode attribute or form properties, if they exist.
|
||||
$shortcode_settings = $this->parse_form_style( $form );
|
||||
// Enqueue styles for the block editor.
|
||||
add_action('enqueue_block_editor_assets', function() use ( $self ) {
|
||||
$self->enqueue_form_styles();
|
||||
}, 1000 );
|
||||
|
||||
// If we have conflicting block and shortcode settings, block settings take priority.
|
||||
$style_settings = ! empty( $block_settings ) ? $block_settings : $shortcode_settings;
|
||||
|
||||
$styles = call_user_func_array( $self->styles, array( $form, $ajax, $settings, $style_settings ) );
|
||||
$scripts = call_user_func_array( $self->scripts, array( $form, $ajax, $settings, $style_settings ) );
|
||||
|
||||
$this->process_form_assets( $styles, $scripts );
|
||||
|
||||
}, 999, 2 );
|
||||
|
||||
add_action( 'gform_enqueue_scripts', function () use ( $self ) {
|
||||
// Enqueue styles in form preview.
|
||||
add_filter( 'gform_preview_styles', function( $styles, $form ) use ( $self ) {
|
||||
global $wp_styles;
|
||||
$queued = $wp_styles->queue;
|
||||
usort( $queued, array( $self, 'sort_enqueues_by_group' ) );
|
||||
$wp_styles->queue = $queued;
|
||||
|
||||
return;
|
||||
}, 1000, 0 );
|
||||
$settings = $this->get_settings( $form['id'] );
|
||||
$self->enqueue_form_assets( $form, false, $settings, array() );
|
||||
return array_unique( array_merge( $styles, $wp_styles->queue ) );
|
||||
}, 10, 2 );
|
||||
|
||||
// Enqueue scripts and styles anywhere a form is loaded (admin or front end). Except for the block editor and form editor, which are handled above.
|
||||
add_action( 'gform_enqueue_scripts', function( $form, $ajax ) use ( $self ) {
|
||||
$settings = $this->get_settings( $form['id'] );
|
||||
$style_settings = $this->parse_form_style( $form );
|
||||
$self->enqueue_form_assets( $form, $ajax, $settings, $style_settings );
|
||||
}, 1000, 4 );
|
||||
|
||||
// Adds theme layer styles to the no conflict list so that they get enqueued when no conflict mode is enabled.
|
||||
add_filter( 'gform_noconflict_styles', function ( $styles ) {
|
||||
return array_unique( array_merge( $styles, $this->_no_conflict_styles ) );
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues the scripts and styles for a form in the appropriate order and group.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param array $form The form to enqueue scripts and styles for.
|
||||
* @param bool $ajax Whether the form is being loaded via AJAX.
|
||||
* @param array $settings The settings for the form.
|
||||
* @param array $style_settings The custom styles defined when embedding a form via the block editor or via the shortcode.
|
||||
*/
|
||||
protected function enqueue_form_assets( $form, $ajax, $settings, $style_settings ) {
|
||||
|
||||
$styles = call_user_func_array( $this->styles, array( $form, $ajax, $settings, $style_settings ) );
|
||||
$scripts = call_user_func_array( $this->scripts, array( $form, $ajax, $settings, $style_settings ) );
|
||||
$this->process_form_assets( $styles, $scripts );
|
||||
|
||||
$this->sort_enqueued_styles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue the styles for a form in the appropriate order and group.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param array $form The form to enqueue styles for. Optional. Some pages such as the block editor page won't have a form context.
|
||||
* @param array $settings The settings for the form.
|
||||
*/
|
||||
protected function enqueue_form_styles( $form = array(), $settings = array() ) {
|
||||
$styles = call_user_func_array( $this->styles, array( $form, false, $settings ) );
|
||||
$this->process_styles( $styles );
|
||||
|
||||
$this->sort_enqueued_styles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts enqueued styles by group. See {@see Asset_Enqueue_Output_Engine::sort_enqueues_by_group()} for more information.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
public function sort_enqueued_styles() {
|
||||
global $wp_styles;
|
||||
|
||||
// Sort styles by group.
|
||||
$queued = $wp_styles->queue;
|
||||
usort( $queued, array( $this, 'sort_enqueues_by_group' ) );
|
||||
$wp_styles->queue = $queued;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts enqueued styles by group. Core styles are always first within their respective groups.
|
||||
* Groups are "reset", "foundation", "framework", and "theme". Groups are sorted in that order, and within each group, core styles are always first followed by other styles.
|
||||
* For example, if an add-on has a style in the "foundation" and "framework" groups, styles will be sorted in the following order:
|
||||
* 1. Core reset style
|
||||
* 2. Core foundation style
|
||||
* 3. Add-on foundation style
|
||||
* 4. Core framework style
|
||||
* 5. Add-on framework style
|
||||
* 6. Core theme style
|
||||
*
|
||||
* @since 2.7.4
|
||||
*
|
||||
* @param string $a Style handle.
|
||||
* @param string $b Style handle.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function sort_enqueues_by_group( $a, $b ) {
|
||||
$comp_keys = array_keys( self::$groups );
|
||||
|
||||
@@ -159,8 +255,8 @@ class Asset_Enqueue_Output_Engine extends Output_Engine {
|
||||
*
|
||||
* @since 2.7.4
|
||||
*
|
||||
* @param array $styles Styles to enqueue
|
||||
* @param array $scripts Scripts to enqueue
|
||||
* @param array $styles Styles to enqueue.
|
||||
* @param array $scripts Scripts to enqueue.
|
||||
*/
|
||||
public function process_form_assets( $styles, $scripts ) {
|
||||
foreach ( $scripts as $script_args ) {
|
||||
@@ -174,6 +270,13 @@ class Asset_Enqueue_Output_Engine extends Output_Engine {
|
||||
$this->process_styles( $styles );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue the styles of a form.
|
||||
*
|
||||
* @since Unknown
|
||||
*
|
||||
* @param array $styles An array of style slugs to be enqued.
|
||||
*/
|
||||
private function process_styles( $styles ) {
|
||||
foreach( $styles as $key => $style_args ) {
|
||||
if ( ! is_numeric( $key ) ) {
|
||||
@@ -193,6 +296,8 @@ class Asset_Enqueue_Output_Engine extends Output_Engine {
|
||||
}
|
||||
|
||||
call_user_func_array( 'wp_enqueue_style', $style_args );
|
||||
|
||||
$this->add_no_conflict_style( $style_args[0] );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
!function(){var r=CryptoJS,h=r.lib.WordArray;r.enc.Base64={stringify:function(r){var a=r.words,t=r.sigBytes,n=this._map;r.clamp(),r=[];for(var i=0;i<t;i+=3)for(var e=(a[i>>>2]>>>24-i%4*8&255)<<16|(a[i+1>>>2]>>>24-(i+1)%4*8&255)<<8|a[i+2>>>2]>>>24-(i+2)%4*8&255,f=0;f<4&&i+.75*f<t;f++)r.push(n.charAt(e>>>6*(3-f)&63));if(a=n.charAt(64))for(;r.length%4;)r.push(a);return r.join("")},parse:function(r){var a=r.length,t=this._map;(e=t.charAt(64))&&-1!=(e=r.indexOf(e))&&(a=e);for(var n,i,e=[],f=0,c=0;c<a;c++)c%4&&(n=t.indexOf(r.charAt(c-1))<<c%4*2,i=t.indexOf(r.charAt(c))>>>6-c%4*2,e[f>>>2]|=(n|i)<<24-f%4*8,f++);return h.create(e,f)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}}();
|
||||
(()=>{var r=CryptoJS,c=r.lib.WordArray;r.enc.Base64={stringify:function(r){var a=r.words,t=r.sigBytes,n=this._map;r.clamp(),r=[];for(var e=0;e<t;e+=3)for(var i=(a[e>>>2]>>>24-e%4*8&255)<<16|(a[e+1>>>2]>>>24-(e+1)%4*8&255)<<8|a[e+2>>>2]>>>24-(e+2)%4*8&255,f=0;f<4&&e+.75*f<t;f++)r.push(n.charAt(i>>>6*(3-f)&63));if(a=n.charAt(64))for(;r.length%4;)r.push(a);return r.join("")},parse:function(r){var a=r.length,t=this._map;(i=t.charAt(64))&&-1!=(i=r.indexOf(i))&&(a=i);for(var n,e,i=[],f=0,h=0;h<a;h++)h%4&&(n=t.indexOf(r.charAt(h-1))<<h%4*2,e=t.indexOf(r.charAt(h))>>>6-h%4*2,i[f>>>2]|=(n|e)<<24-f%4*8,f++);return c.create(i,f)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}})();
|
||||
Reference in New Issue
Block a user