array(), 'inactive' => array() );
/**
* Class constructor which hooks the instance into the WordPress init action
*/
function __construct() {
$this->update_path();
add_action( 'init', array( $this, 'init' ) );
if ( $this->_enable_rg_autoupgrade ) {
require_once( 'class-gf-auto-upgrade.php' );
$is_gravityforms_supported = $this->is_gravityforms_supported( $this->_min_gravityforms_version );
new GFAutoUpgrade( $this->_slug, $this->_version, $this->_min_gravityforms_version, $this->_title, $this->_full_path, $this->get_path(), $this->_url, $is_gravityforms_supported );
}
$this->pre_init();
}
/**
* Registers an addon so that it gets initialized appropriately
*
* @param string $class - The class name
* @param string $overrides - Specify the class to replace/override
*/
public static function register( $class, $overrides = null ) {
//Ignore classes that have been marked as inactive
if ( in_array( $class, self::$_registered_addons['inactive'] ) ) {
return;
}
//Mark classes as active. Override existing active classes if they are supposed to be overridden
$index = array_search( $overrides, self::$_registered_addons['active'] );
if ( $index !== false ) {
self::$_registered_addons['active'][ $index ] = $class;
} else {
self::$_registered_addons['active'][] = $class;
}
//Mark overridden classes as inactive.
if ( ! empty( $overrides ) ) {
self::$_registered_addons['inactive'][] = $overrides;
}
}
/**
* Gets all active, registered Add-Ons.
*
* @since Unknown
* @access public
*
* @uses GFAddOn::$_registered_addons
*
* @return array Active, registered Add-Ons.
*/
public static function get_registered_addons() {
return self::$_registered_addons['active'];
}
/**
* Initializes all addons.
*/
public static function init_addons() {
//Removing duplicate add-ons
$active_addons = array_unique( self::$_registered_addons['active'] );
foreach ( $active_addons as $addon ) {
call_user_func( array( $addon, 'get_instance' ) );
}
}
/**
* Gets executed before all init functions. Override this function to perform initialization tasks that must be done prior to init
*/
public function pre_init() {
if ( $this->is_gravityforms_supported() ) {
//Entry meta
if ( $this->method_is_overridden( 'get_entry_meta' ) ) {
add_filter( 'gform_entry_meta', array( $this, 'get_entry_meta' ), 10, 2 );
}
}
}
/**
* Plugin starting point. Handles hooks and loading of language files.
*/
public function init() {
$this->load_text_domain();
add_filter( 'gform_logging_supported', array( $this, 'set_logging_supported' ) );
add_action( 'gform_post_upgrade', array( $this, 'post_gravityforms_upgrade' ), 10, 3 );
// Get minimum requirements state.
$meets_requirements = $this->meets_minimum_requirements();
if ( RG_CURRENT_PAGE == 'admin-ajax.php' ) {
//If gravity forms is supported, initialize AJAX
if ( $this->is_gravityforms_supported() && $meets_requirements['meets_requirements'] ) {
$this->init_ajax();
}
} elseif ( is_admin() ) {
$this->init_admin();
} else {
if ( $this->is_gravityforms_supported() && $meets_requirements['meets_requirements'] ) {
$this->init_frontend();
}
}
}
/**
* Override this function to add initialization code (i.e. hooks) for the admin site (WP dashboard)
*/
public function init_admin() {
// enqueues admin scripts
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ), 10, 0 );
// message enforcing min version of Gravity Forms
if ( isset( $this->_min_gravityforms_version ) && RG_CURRENT_PAGE == 'plugins.php' ) {
add_action( 'after_plugin_row_' . $this->get_path(), array( $this, 'plugin_row' ), 10, 2 );
}
// STOP HERE IF GRAVITY FORMS IS NOT SUPPORTED
if ( isset( $this->_min_gravityforms_version ) && ! $this->is_gravityforms_supported( $this->_min_gravityforms_version ) ) {
return;
}
// STOP HERE IF CANNOT PASS MINIMUM REQUIREMENTS CHECK.
$meets_requirements = $this->meets_minimum_requirements();
if ( ! $meets_requirements['meets_requirements'] ) {
$this->failed_requirements_init();
return;
}
$this->setup();
// Add form settings only when there are form settings fields configured or form_settings() method is implemented
if ( self::has_form_settings_page() ) {
$this->form_settings_init();
}
// Add plugin page when there is a plugin page configured or plugin_page() method is implemented
if ( self::has_plugin_page() ) {
$this->plugin_page_init();
}
// Add addon settings page only when there are addon settings fields configured or settings_page() method is implemented
if ( self::has_plugin_settings_page() ) {
if ( $this->current_user_can_any( $this->_capabilities_settings_page ) ) {
$this->plugin_settings_init();
}
}
// creates the top level app left menu
if ( self::has_app_menu() ) {
if ( $this->current_user_can_any( $this->_capabilities_app_menu ) ) {
add_action( 'admin_menu', array( $this, 'create_app_menu' ) );
}
}
// Members plugin integration.
if ( $this->has_members_plugin( ) ) {
add_action( 'members_register_cap_groups', array( $this, 'members_register_cap_group' ), 11 );
add_action( 'members_register_caps', array( $this, 'members_register_caps' ), 11 );
}
// User Role Editor integration.
add_filter( 'ure_capabilities_groups_tree', array( $this, 'filter_ure_capabilities_groups_tree' ), 11 );
add_filter( 'ure_custom_capability_groups', array( $this, 'filter_ure_custom_capability_groups' ), 10, 2 );
// Results page
if ( $this->method_is_overridden( 'get_results_page_config' ) ) {
$results_page_config = $this->get_results_page_config();
$results_capabilities = rgar( $results_page_config, 'capabilities' );
if ( $results_page_config && $this->current_user_can_any( $results_capabilities ) ) {
$this->results_page_init( $results_page_config );
}
}
// Locking
if ( $this->method_is_overridden( 'get_locking_config' ) ) {
require_once( GFCommon::get_base_path() . '/includes/locking/class-gf-locking.php' );
require_once( 'class-gf-addon-locking.php' );
$config = $this->get_locking_config();
new GFAddonLocking( $config, $this );
}
// No conflict scripts
add_filter( 'gform_noconflict_scripts', array( $this, 'register_noconflict_scripts' ) );
add_filter( 'gform_noconflict_styles', array( $this, 'register_noconflict_styles' ) );
add_action( 'gform_enqueue_scripts', array( $this, 'enqueue_scripts' ), 10, 2 );
}
/**
* Override this function to add initialization code (i.e. hooks) for the public (customer facing) site
*/
public function init_frontend() {
$this->setup();
add_filter( 'gform_preview_styles', array( $this, 'enqueue_preview_styles' ), 10, 2 );
add_filter( 'gform_print_styles', array( $this, 'enqueue_print_styles' ), 10, 2 );
add_action( 'gform_enqueue_scripts', array( $this, 'enqueue_scripts' ), 10, 2 );
}
/**
* Override this function to add AJAX hooks or to add initialization code when an AJAX request is being performed
*/
public function init_ajax() {
if ( rgpost( 'view' ) == 'gf_results_' . $this->_slug ) {
require_once( GFCommon::get_base_path() . '/tooltips.php' );
require_once( 'class-gf-results.php' );
$gf_results = new GFResults( $this->_slug, $this->get_results_page_config() );
add_action( 'wp_ajax_gresults_get_results_gf_results_' . $this->_slug, array( $gf_results, 'ajax_get_results' ) );
add_action( 'wp_ajax_gresults_get_more_results_gf_results_' . $this->_slug, array( $gf_results, 'ajax_get_more_results' ) );
} elseif ( $this->method_is_overridden( 'get_locking_config' ) ) {
require_once( GFCommon::get_base_path() . '/includes/locking/class-gf-locking.php' );
require_once( 'class-gf-addon-locking.php' );
$config = $this->get_locking_config();
new GFAddonLocking( $config, $this );
}
}
//-------------- Minimum Requirements Check ---------------
/**
* Override this function to provide a list of requirements needed to use Add-On.
*
* Custom requirements can be defined by adding a callback to the minimum requirements array.
* A custom requirement receives and should return an array with two parameters:
* bool $meets_requirements If the custom requirements check passed.
* array $errors An array of error messages to present to the user.
*
* Following is an example of the array that is expected to be returned by this function:
* @example https://gist.github.com/JeffMatson/a8d23e16e333e5116060906c6f091aa7
*
* @since 2.2
* @access public
*
* @return array
*/
public function minimum_requirements() {
return array();
}
/**
* Performs a check to see if WordPress environment meets minimum requirements need to use Add-On.
*
* @since 2.2
* @access public
*
* @uses GFAddOn::minimum_requirements()
* @uses GFAddOn::get_slug()
*
* @return bool|array
*/
public function meets_minimum_requirements() {
// Get minimum requirements.
$requirements = $this->minimum_requirements();
// Prepare response.
$meets_requirements = array( 'meets_requirements' => true, 'errors' => array() );
// If no minimum requirements are defined, return.
if ( empty( $requirements ) ) {
return $meets_requirements;
}
// Loop through requirements.
foreach ( $requirements as $requirement_type => $requirement ) {
// If requirement is a callback, run it.
if ( is_callable( $requirement ) ) {
$meets_requirements = call_user_func( $requirement, $meets_requirements );
continue;
}
// Set requirement type to lowercase.
$requirement_type = strtolower( $requirement_type );
// Run base requirement checks.
switch ( $requirement_type ) {
case 'add-ons':
// Initialize active Add-Ons array.
$active_addons = array();
// Loop through active Add-Ons.
foreach ( self::$_registered_addons['active'] as $active_addon ) {
// Get Add-On instance.
$active_addon = call_user_func( array( $active_addon, 'get_instance' ) );
// Add to active Add-Ons array.
$active_addons[ $active_addon->get_slug() ] = array(
'slug' => $active_addon->get_slug(),
'title' => $active_addon->_title,
'version' => $active_addon->_version,
);
}
// Loop through Add-Ons.
foreach ( $requirement as $addon_slug => $addon_requirements ) {
// If Add-On requirements is not an array, set Add-On slug to requirements value.
if ( ! is_array( $addon_requirements ) ) {
$addon_slug = $addon_requirements;
}
// If Add-On is not active, set error.
if ( ! isset( $active_addons[ $addon_slug ] ) ) {
// Get Add-On name.
$addon_name = rgar( $addon_requirements, 'name' ) ? $addon_requirements['name'] : $addon_slug;
$meets_requirements['meets_requirements'] = false;
$meets_requirements['errors'][] = sprintf( esc_html__( 'Required Gravity Forms Add-On is missing: %s.', 'gravityforms' ), $addon_name );
continue;
}
// If Add-On does not meet minimum version, set error.
if ( rgar( $addon_requirements, 'version' ) && ! version_compare( $active_addons[ $addon_slug ]['version'], $addon_requirements['version'], '>=' ) ) {
$meets_requirements['meets_requirements'] = false;
$meets_requirements['errors'][] = sprintf( esc_html__( 'Required Gravity Forms Add-On "%s" does not meet minimum version requirement: %s.', 'gravityforms' ), $active_addons[ $addon_slug ]['title'], $addon_requirements['version'] );
continue;
}
}
break;
case 'plugins':
// Loop through plugins.
foreach ( $requirement as $plugin_path => $plugin_name ) {
// If plugin name is not defined, set plugin path to name.
if ( is_int( $plugin_path ) ) {
$plugin_path = $plugin_name;
}
// If plugin is not active, set error.
if ( ! is_plugin_active( $plugin_path ) ) {
$meets_requirements['meets_requirements'] = false;
$meets_requirements['errors'][] = sprintf( esc_html__( 'Required WordPress plugin is missing: %s.', 'gravityforms' ), $plugin_name );
continue;
}
}
case 'php':
// Check version.
if ( rgar( $requirement, 'version' ) && ! version_compare( PHP_VERSION, $requirement['version'], '>=' ) ) {
$meets_requirements['meets_requirements'] = false;
$meets_requirements['errors'][] = sprintf( esc_html__( 'Current PHP version (%s) does not meet minimum PHP version requirement (%s).', 'gravityforms' ), PHP_VERSION, $requirement['version'] );
}
// Check extensions.
if ( rgar( $requirement, 'extensions' ) ) {
// Loop through extensions.
foreach ( $requirement['extensions'] as $extension => $extension_requirements ) {
// If extension requirements is not an array, set extension name to requirements value.
if ( ! is_array( $extension_requirements ) ) {
$extension = $extension_requirements;
}
// If PHP extension is not loaded, set error.
if ( ! extension_loaded( $extension ) ) {
$meets_requirements['meets_requirements'] = false;
$meets_requirements['errors'][] = sprintf( esc_html__( 'Required PHP extension missing: %s', 'gravityforms' ), $extension );
continue;
}
// If PHP extension does not meet minimum version, set error.
if ( rgar( $extension_requirements, 'version' ) && ! version_compare( phpversion( $extension ), $extension_requirements['version'], '>=' ) ) {
$meets_requirements['meets_requirements'] = false;
$meets_requirements['errors'][] = sprintf( esc_html__( 'Required PHP extension "%s" does not meet minimum version requirement: %s.', 'gravityforms' ), $extension, $extension_requirements['version'] );
continue;
}
}
}
// Check functions.
if ( rgar( $requirement, 'functions' ) ) {
// Loop through functions.
foreach ( $requirement['functions'] as $function ) {
if ( ! function_exists( $function ) ) {
$meets_requirements['meets_requirements'] = false;
$meets_requirements['errors'][] = sprintf( esc_html__( 'Required PHP function missing: %s', 'gravityforms' ), $function );
}
}
}
break;
case 'wordpress':
// Check version.
if ( rgar( $requirement, 'version' ) && ! version_compare( get_bloginfo( 'version' ), $requirement['version'], '>=' ) ) {
$meets_requirements['meets_requirements'] = false;
$meets_requirements['errors'][] = sprintf( esc_html__( 'Current WordPress version (%s) does not meet minimum WordPress version requirement (%s).', 'gravityforms' ), get_bloginfo( 'version' ), $requirement['version'] );
}
break;
}
}
return $meets_requirements;
}
/**
* Register failed requirements page under Gravity Forms settings.
*
* @since 2.2
* @access public
*
* @uses GFAddOn::current_user_can_any()
* @uses GFAddOn::get_short_title()
* @uses GFAddOn::plugin_settings_title()
* @uses GFCommon::get_base_path()
* @uses RGForms::add_settings_page()
*/
public function failed_requirements_init() {
// Get failed requirements.
$failed_requirements = $this->meets_minimum_requirements();
// Prepare errors list.
$errors = '';
foreach ( $failed_requirements['errors'] as $error ) {
$errors .= sprintf( '
%s
', esc_html( $error ) );
}
// Prepare error message.
$error_message = sprintf(
'%s %s%s',
sprintf( esc_html__( '%s is not able to run because your WordPress environment has not met the minimum requirements.', 'gravityforms' ), $this->_title ),
sprintf( esc_html__( 'Please resolve the following issues to use %s:', 'gravityforms' ), $this->get_short_title() ),
$errors
);
// Add error message.
if ( $this->is_form_list() || $this->is_entry_list() || $this->is_form_settings() || $this->is_plugin_settings() || GFForms::get_page() === 'system_status' ) {
GFCommon::add_error_message( $error_message );
}
}
//-------------- Setup ---------------
/**
* Performs upgrade tasks when the version of the Add-On changes. To add additional upgrade tasks, override the upgrade() function, which will only get executed when the plugin version has changed.
*/
public function setup() {
//Upgrading add-on
$installed_version = get_option( 'gravityformsaddon_' . $this->_slug . '_version' );
//Making sure version has really changed. Gets around aggressive caching issue on some sites that cause setup to run multiple times.
if ( $installed_version != $this->_version ) {
$installed_version = GFForms::get_wp_option( 'gravityformsaddon_' . $this->_slug . '_version' );
}
//Upgrade if version has changed
if ( $installed_version != $this->_version ) {
$this->upgrade( $installed_version );
update_option( 'gravityformsaddon_' . $this->_slug . '_version', $this->_version );
}
}
/**
* Override this function to add to add database update scripts or any other code to be executed when the Add-On version changes
*/
public function upgrade( $previous_version ) {
return;
}
/**
* Gets called when Gravity Forms upgrade process is completed. This function is intended to be used internally, override the upgrade() function to execute database update scripts.
* @param $db_version - Current Gravity Forms database version
* @param $previous_db_version - Previous Gravity Forms database version
* @param $force_upgrade - True if this is a request to force an upgrade. False if this is a standard upgrade (due to version change)
*/
public function post_gravityforms_upgrade( $db_version, $previous_db_version, $force_upgrade ){
// Forcing Upgrade
if( $force_upgrade ){
$installed_version = get_option( 'gravityformsaddon_' . $this->_slug . '_version' );
$this->upgrade( $installed_version );
update_option( 'gravityformsaddon_' . $this->_slug . '_version', $this->_version );
}
}
//-------------- Script enqueuing ---------------
/**
* Override this function to provide a list of styles to be enqueued.
* When overriding this function, be sure to call parent::styles() to ensure the base class scripts are enqueued.
* See scripts() for an example of the format expected to be returned.
*/
public function styles() {
$min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG || isset( $_GET['gform_debug'] ) ? '' : '.min';
return array(
array(
'handle' => 'gaddon_form_settings_css',
'src' => GFAddOn::get_gfaddon_base_url() . "/css/gaddon_settings{$min}.css",
'version' => GFCommon::$version,
'enqueue' => array(
array( 'admin_page' => array( 'form_settings', 'plugin_settings', 'plugin_page', 'app_settings' ) ),
)
),
array(
'handle' => 'gaddon_results_css',
'src' => GFAddOn::get_gfaddon_base_url() . "/css/gaddon_results{$min}.css",
'version' => GFCommon::$version,
'enqueue' => array(
array( 'admin_page' => array( 'results' ) ),
)
),
);
}
/**
* Override this function to provide a list of scripts to be enqueued.
* When overriding this function, be sure to call parent::scripts() to ensure the base class scripts are enqueued.
* Following is an example of the array that is expected to be returned by this function:
*
*
*
* array(
* array(
* 'handle' => 'maskedinput',
* 'src' => GFCommon::get_base_url() . '/js/jquery.maskedinput-1.3.min.js',
* 'version' => GFCommon::$version,
* 'deps' => array( 'jquery' ),
* 'in_footer' => false,
*
* // Determines where the script will be enqueued. The script will be enqueued if any of the conditions match.
* 'enqueue' => array(
* // admin_page - Specified one or more pages (known pages) where the script is supposed to be enqueued.
* // To enqueue scripts in the front end (public website), simply don't define this setting.
* array( 'admin_page' => array( 'form_settings', 'plugin_settings' ) ),
*
* // tab - Specifies a form settings or plugin settings tab in which the script is supposed to be enqueued.
* // If none are specified, the script will be enqueued in any of the form settings or plugin_settings page
* array( 'tab' => 'signature'),
*
* // query - Specifies a set of query string ($_GET) values.
* // If all specified query string values match the current requested page, the script will be enqueued
* array( 'query' => 'page=gf_edit_forms&view=settings&id=_notempty_' )
*
* // post - Specifies a set of post ($_POST) values.
* // If all specified posted values match the current request, the script will be enqueued
* array( 'post' => 'posted_field=val' )
* )
* ),
* array(
* 'handle' => 'super_signature_script',
* 'src' => $this->get_base_url() . '/super_signature/ss.js',
* 'version' => $this->_version,
* 'deps' => array( 'jquery'),
* 'callback' => array( $this, 'localize_scripts' ),
* 'strings' => array(
* // Accessible in JavaScript using the global variable "[script handle]_strings"
* 'stringKey1' => __( 'The string', 'gravityforms' ),
* 'stringKey2' => __( 'Another string.', 'gravityforms' )
* )
* "enqueue" => array(
* // field_types - Specifies one or more field types that requires this script.
* // The script will only be enqueued if the current form has a field of any of the specified field types.
* // Only applies when a current form is available.
* array( 'field_types' => array( 'signature' ) )
* )
* )
* );
*
*
*
*/
public function scripts() {
$min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG || isset( $_GET['gform_debug'] ) ? '' : '.min';
return array(
array(
'handle' => 'gform_form_admin',
'enqueue' => array( array( 'admin_page' => array( 'form_settings' ) ) )
),
array(
'handle' => 'gform_gravityforms',
'enqueue' => array( array( 'admin_page' => array( 'form_settings' ) ) )
),
array(
'handle' => 'google_charts',
'src' => 'https://www.google.com/jsapi',
'version' => GFCommon::$version,
'enqueue' => array(
array( 'admin_page' => array( 'results' ) ),
)
),
array(
'handle' => 'gaddon_results_js',
'src' => GFAddOn::get_gfaddon_base_url() . "/js/gaddon_results{$min}.js",
'version' => GFCommon::$version,
'deps' => array( 'jquery', 'sack', 'jquery-ui-resizable', 'gform_datepicker_init', 'google_charts', 'gform_field_filter' ),
'callback' => array( 'GFResults', 'localize_results_scripts' ),
'enqueue' => array(
array( 'admin_page' => array( 'results' ) ),
)
),
array(
'handle' => 'gaddon_repeater',
'src' => GFAddOn::get_gfaddon_base_url() . "/js/repeater{$min}.js",
'version' => GFCommon::$version,
'deps' => array( 'jquery' ),
'enqueue' => array(
array(
'admin_page' => array( 'form_settings' ),
),
),
),
array(
'handle' => 'gaddon_fieldmap_js',
'src' => GFAddOn::get_gfaddon_base_url() . "/js/gaddon_fieldmap{$min}.js",
'version' => GFCommon::$version,
'deps' => array( 'jquery', 'gaddon_repeater' ),
'enqueue' => array(
array( 'admin_page' => array( 'form_settings' ) ),
)
),
array(
'handle' => 'gaddon_genericmap_js',
'src' => GFAddOn::get_gfaddon_base_url() . "/js/gaddon_genericmap{$min}.js",
'version' => GFCommon::$version,
'deps' => array( 'jquery', 'gaddon_repeater' ),
'enqueue' => array(
array( 'admin_page' => array( 'form_settings' ) ),
)
),
array(
'handle' => 'gaddon_selectcustom_js',
'src' => GFAddOn::get_gfaddon_base_url() . "/js/gaddon_selectcustom{$min}.js",
'version' => GFCommon::$version,
'deps' => array( 'jquery' ),
'enqueue' => array(
array( 'admin_page' => array( 'form_settings', 'plugin_settings' ) ),
)
),
);
}
/**
* Target of admin_enqueue_scripts and gform_enqueue_scripts hooks.
* Not intended to be overridden by child classes.
* In order to enqueue scripts and styles, override the scripts() and styles() functions
*
* @ignore
*/
public function enqueue_scripts( $form = '', $is_ajax = false ) {
if ( empty( $form ) ) {
$form = $this->get_current_form();
}
//Enqueueing scripts
$scripts = $this->scripts();
foreach ( $scripts as $script ) {
$src = isset( $script['src'] ) ? $script['src'] : false;
$deps = isset( $script['deps'] ) ? $script['deps'] : array();
$version = array_key_exists( 'version', $script ) ? $script['version'] : false;
$in_footer = isset( $script['in_footer'] ) ? $script['in_footer'] : false;
wp_register_script( $script['handle'], $src, $deps, $version, $in_footer );
if ( isset( $script['enqueue'] ) && $this->_can_enqueue_script( $script['enqueue'], $form, $is_ajax ) ) {
$this->add_no_conflict_scripts( array( $script['handle'] ) );
wp_enqueue_script( $script['handle'] );
if ( isset( $script['strings'] ) ) {
wp_localize_script( $script['handle'], $script['handle'] . '_strings', $script['strings'] );
}
if ( isset( $script['callback'] ) && is_callable( $script['callback'] ) ) {
$args = compact( 'form', 'is_ajax' );
call_user_func_array( $script['callback'], $args );
}
}
}
//Enqueueing styles
$styles = $this->styles();
foreach ( $styles as $style ) {
$src = isset( $style['src'] ) ? $style['src'] : false;
$deps = isset( $style['deps'] ) ? $style['deps'] : array();
$version = array_key_exists( 'version', $style ) ? $style['version'] : false;
$media = isset( $style['media'] ) ? $style['media'] : 'all';
wp_register_style( $style['handle'], $src, $deps, $version, $media );
if ( $this->_can_enqueue_script( $style['enqueue'], $form, $is_ajax ) ) {
$this->add_no_conflict_styles( array( $style['handle'] ) );
if ( $this->is_preview() ) {
$this->_preview_styles[] = $style['handle'];
} elseif ( $this->is_print() ) {
$this->_print_styles[] = $style['handle'];
} else {
wp_enqueue_style( $style['handle'] );
}
}
}
}
/**
* Target of gform_preview_styles. Enqueue styles to the preview page.
* Not intended to be overridden by child classes
*
* @ignore
*/
public function enqueue_preview_styles( $preview_styles, $form ) {
return array_merge( $preview_styles, $this->_preview_styles );
}
/**
* Target of gform_print_styles. Enqueue styles to the print entry page.
* Not intended to be overridden by child classes
*
* @ignore
*/
public function enqueue_print_styles( $print_styles, $form ) {
if ( false === $print_styles ) {
$print_styles = array();
}
$styles = $this->styles();
foreach ( $styles as $style ) {
if ( $this->_can_enqueue_script( $style['enqueue'], $form, false ) ) {
$this->add_no_conflict_styles( array( $style['handle'] ) );
$src = isset( $style['src'] ) ? $style['src'] : false;
$deps = isset( $style['deps'] ) ? $style['deps'] : array();
$version = isset( $style['version'] ) ? $style['version'] : false;
$media = isset( $style['media'] ) ? $style['media'] : 'all';
wp_register_style( $style['handle'], $src, $deps, $version, $media );
$print_styles[] = $style['handle'];
}
}
return array_merge( $print_styles, $this->_print_styles );
}
/**
* Adds scripts to the list of white-listed no conflict scripts.
*
* @param $scripts
*/
private function add_no_conflict_scripts( $scripts ) {
$this->_no_conflict_scripts = array_merge( $scripts, $this->_no_conflict_scripts );
}
/**
* Adds styles to the list of white-listed no conflict styles.
*
* @param $styles
*/
private function add_no_conflict_styles( $styles ) {
$this->_no_conflict_styles = array_merge( $styles, $this->_no_conflict_styles );
}
private function _can_enqueue_script( $enqueue_conditions, $form = array(), $is_ajax = false ) {
if ( empty( $enqueue_conditions ) ) {
return false;
}
foreach ( $enqueue_conditions as $condition ) {
if ( is_callable( $condition ) ) {
$callback_matches = call_user_func( $condition, $form, $is_ajax );
if ( $callback_matches ) {
return true;
}
} else {
$query_matches = isset( $condition['query'] ) ? $this->_request_condition_matches( $_GET, $condition['query'] ) : true;
$post_matches = isset( $condition['post'] ) ? $this->_request_condition_matches( $_POST, $condition['post'] ) : true;
$admin_page_matches = isset( $condition['admin_page'] ) ? $this->_page_condition_matches( $condition['admin_page'], rgar( $condition, 'tab' ) ) : true;
$field_type_matches = isset( $condition['field_types'] ) ? $this->_field_condition_matches( $condition['field_types'], $form ) : true;
if ( $query_matches && $post_matches && $admin_page_matches && $field_type_matches ) {
return true;
}
}
}
return false;
}
private function _request_condition_matches( $request, $query ) {
parse_str( $query, $query_array );
foreach ( $query_array as $key => $value ) {
switch ( $value ) {
case '_notempty_' :
if ( rgempty( $key, $request ) ) {
return false;
}
break;
case '_empty_' :
if ( ! rgempty( $key, $request ) ) {
return false;
}
break;
default :
if ( rgar( $request, $key ) != $value ) {
return false;
}
break;
}
}
return true;
}
private function _page_condition_matches( $pages, $tab ) {
if ( ! is_array( $pages ) ) {
$pages = array( $pages );
}
foreach ( $pages as $page ) {
switch ( $page ) {
case 'form_editor' :
if ( $this->is_form_editor() ) {
return true;
}
break;
case 'form_list' :
if ( $this->is_form_list() ) {
return true;
}
break;
case 'form_settings' :
if ( $this->is_form_settings( $tab ) ) {
return true;
}
break;
case 'plugin_settings' :
if ( $this->is_plugin_settings( $tab ) ) {
return true;
}
break;
case 'app_settings' :
if ( $this->is_app_settings( $tab ) ) {
return true;
}
break;
case 'plugin_page' :
if ( $this->is_plugin_page() ) {
return true;
}
break;
case 'entry_list' :
if ( $this->is_entry_list() ) {
return true;
}
break;
case 'entry_view' :
if ( $this->is_entry_view() ) {
return true;
}
break;
case 'entry_edit' :
if ( $this->is_entry_edit() ) {
return true;
}
break;
case 'results' :
if ( $this->is_results() ) {
return true;
}
break;
case 'customizer' :
if ( is_customize_preview() ) {
return true;
}
break;
}
}
return false;
}
private function _field_condition_matches( $field_types, $form ) {
if ( ! is_array( $field_types ) ) {
$field_types = array( $field_types );
}
/* @var GF_Field[] $fields */
$fields = GFAPI::get_fields_by_type( $form, $field_types );
if ( count( $fields ) > 0 ) {
foreach ( $fields as $field ) {
if ( $field->is_administrative() && ! $field->allowsPrepopulate && ! GFForms::get_page() ) {
continue;
}
return true;
}
}
return false;
}
/**
* Target for the gform_noconflict_scripts filter. Adds scripts to the list of white-listed no conflict scripts.
*
* Not intended to be overridden or called directed by Add-Ons.
*
* @ignore
*
* @param array $scripts Array of scripts to be white-listed
*
* @return array
*/
public function register_noconflict_scripts( $scripts ) {
//registering scripts with Gravity Forms so that they get enqueued when running in no-conflict mode
return array_merge( $scripts, $this->_no_conflict_scripts );
}
/**
* Target for the gform_noconflict_styles filter. Adds styles to the list of white-listed no conflict scripts.
*
* Not intended to be overridden or called directed by Add-Ons.
*
* @ignore
*
* @param array $styles Array of styles to be white-listed
*
* @return array
*/
public function register_noconflict_styles( $styles ) {
//registering styles with Gravity Forms so that they get enqueued when running in no-conflict mode
return array_merge( $styles, $this->_no_conflict_styles );
}
//-------------- Entry meta --------------------------------------
/**
* Override this method to activate and configure entry meta.
*
*
* @param array $entry_meta An array of entry meta already registered with the gform_entry_meta filter.
* @param int $form_id The form id
*
* @return array The filtered entry meta array.
*/
public function get_entry_meta( $entry_meta, $form_id ) {
return $entry_meta;
}
//-------------- Results page --------------------------------------
/**
* Returns the configuration for the results page. By default this is not activated.
* To activate the results page override this function and return an array with the configuration data.
*
* Example:
* public function get_results_page_config() {
* return array(
* "title" => 'Quiz Results',
* "capabilities" => array("gravityforms_quiz_results"),
* "callbacks" => array(
* "fields" => array($this, 'results_fields'),
* "calculation" => array($this, 'results_calculation'),
* "markup" => array($this, 'results_markup'),
* )
* );
* }
*
*/
public function get_results_page_config() {
return false;
}
/**
* Initializes the result page functionality. To activate result page functionality, override the get_results_page_config() function.
*
* @param $results_page_config - configuration returned by get_results_page_config()
*/
public function results_page_init( $results_page_config ) {
require_once( 'class-gf-results.php' );
if ( isset( $results_page_config['callbacks']['filters'] ) ) {
add_filter( 'gform_filters_pre_results', $results_page_config['callbacks']['filters'], 10, 2 );
}
if ( isset( $results_page_config['callbacks']['filter_ui'] ) ) {
add_filter( 'gform_filter_ui', $results_page_config['callbacks']['filter_ui'], 10, 5 );
}
$gf_results = new GFResults( $this->_slug, $results_page_config );
$gf_results->init();
}
//-------------- Logging integration --------------------------------------
public function set_logging_supported( $plugins ) {
$plugins[ $this->_slug ] = $this->_title;
return $plugins;
}
// # PERMISSIONS ---------------------------------------------------------------------------------------------------
/**
* Checks whether the Members plugin is installed and activated.
*
* Not intended to be overridden or called directly by Add-Ons.
*
* @ignore
*
* @return bool
*/
public function has_members_plugin() {
return GFForms::has_members_plugin();
}
/**
* Register the Gravity Forms Add-Ons capabilities group with the Members plugin.
*
* @since 2.4
* @access public
*/
public function members_register_cap_group() {
members_register_cap_group(
'gravityforms_addons',
array(
'label' => esc_html__( 'GF Add-Ons', 'gravityforms' ),
'icon' => 'dashicons-gravityforms',
'caps' => array(),
)
);
}
/**
* Register the Add-On capabilities and their human readable labels with the Members plugin.
*
* @since 2.4
* @access public
*
* @uses GFAddOn::get_short_title()
*/
public function members_register_caps() {
// Get capabilities.
$caps = $this->get_members_caps();
// If no capabilities were found, exit.
if ( empty( $caps ) ) {
return;
}
// Register capabilities.
foreach ( $caps as $cap => $label ) {
members_register_cap(
$cap,
array(
'label' => sprintf( '%s: %s', $this->get_short_title(), $label ),
'group' => 'gravityforms_addons',
)
);
}
}
/**
* Get Add-On capabilities and their human readable labels.
*
* @since 2.4
* @access public
*
* @return array
*/
public function get_members_caps() {
// Initialize capabilities array.
$caps = array();
// Add capabilities.
if ( ! empty( $this->_capabilities_form_settings ) && is_string( $this->_capabilities_form_settings ) ) {
$caps[ $this->_capabilities_form_settings ] = esc_html__( 'Form Settings', 'gravityforms' );
}
if ( ! empty( $this->_capabilities_uninstall ) && is_string( $this->_capabilities_uninstall ) ) {
$caps[ $this->_capabilities_uninstall ] = esc_html__( 'Uninstall', 'gravityforms' );
}
if ( ! empty( $this->_capabilities_plugin_page ) && is_string( $this->_capabilities_plugin_page ) ) {
$caps[ $this->_capabilities_plugin_page ] = esc_html__( 'Add-On Page', 'gravityforms' );
}
if ( ! empty( $this->_capabilities_settings_page ) && is_string( $this->_capabilities_settings_page ) ) {
$caps[ $this->_capabilities_settings_page ] = esc_html__( 'Add-On Settings', 'gravityforms' );
}
return $caps;
}
/**
* Register Gravity Forms Add-Ons capabilities group with User Role Editor plugin.
*
* @since 2.4
*
* @param array $groups Existing capabilities groups.
*
* @return array
*/
public static function filter_ure_capabilities_groups_tree( $groups = array() ) {
$groups['gravityforms_addons'] = array(
'caption' => esc_html__( 'Gravity Forms Add-Ons', 'gravityforms' ),
'parent' => 'gravityforms',
'level' => 3,
);
return $groups;
}
/**
* Register Gravity Forms capabilities with Gravity Forms group in User Role Editor plugin.
*
* @since 2.4
*
* @param array $groups Current capability groups.
* @param string $cap_id Capability identifier.
*
* @return array
*/
public function filter_ure_custom_capability_groups( $groups = array(), $cap_id = '' ) {
// Get Add-On capabilities.
$caps = $this->_capabilities;
// If capability belongs to Add-On, register it to group.
if ( in_array( $cap_id, $caps, true ) ) {
$groups[] = 'gravityforms_addons';
}
return $groups;
}
/**
* Checks whether the current user is assigned to a capability or role.
*
* @since Unknown
* @access public
*
* @param string|array $caps An string or array of capabilities to check
*
* @return bool Returns true if the current user is assigned to any of the capabilities.
*/
public function current_user_can_any( $caps ) {
return GFCommon::current_user_can_any( $caps );
}
//------- Settings Helper Methods (Common to all settings pages) -------------------
/***
* Renders the UI of all settings page based on the specified configuration array $sections
*
* @param array $sections - Configuration array containing all fields to be rendered grouped into sections
*/
public function render_settings( $sections ) {
if ( ! $this->has_setting_field_type( 'save', $sections ) ) {
$sections = $this->add_default_save_button( $sections );
}
?>
setting_dependency_met( rgar( $section, 'dependency' ) ) ) {
$this->single_section( $section, $is_first );
}
$is_first = false;
}
}
/***
* Displays the UI for a field section
*
* @param array $section - The section to be displayed
* @param bool $is_first - true for the first section in the list, false for all others
*/
public function single_section( $section, $is_first = false ) {
extract(
wp_parse_args(
$section, array(
'title' => false,
'description' => false,
'id' => '',
'class' => false,
'style' => '',
'tooltip' => false,
'tooltip_class' => ''
)
)
);
$classes = array( 'gaddon-section' );
if ( $is_first ) {
$classes[] = 'gaddon-first-section';
}
if ( $class )
$classes[] = $class;
?>
';
return $checkbox_item;
}
/**
* Returns the markup for an individual checkbox input and its associated label
*
* @param $choice - Choice array with all configured properties
* @param $attributes - String containing all the attributes for the input tag.
* @param $value - Currently selection (1 if field has been checked. 0 or null otherwise)
* @param $tooltip - String containing a tooltip for this checkbox item.
*
* @return string - The markup of an individual checkbox input and its associated label
*/
public function checkbox_input( $choice, $attributes, $value, $tooltip ) {
$icon_tag = '';
if ( rgar( $choice, 'icon' ) ) {
/* Get the defined icon. */
$icon = rgar( $choice, 'icon' ) ? $choice['icon'] : 'fa-cog';
/* Set icon tag based on icon type. */
if ( filter_var( $icon, FILTER_VALIDATE_URL ) ) {
$icon_tag = '';
} else {
$icon_tag = '';
}
$icon_tag .= ' ';
}
$markup = '';
$markup .= '';
return $markup;
}
/***
* Renders and initializes a radio field or a collection of radio fields based on the $field array
*
* @param array $field - Field array containing the configuration options of this field
* @param bool $echo = true - true to echo the output to the screen, false to simply return the contents as a string
*
* @return string Returns the markup for the radio buttons
*
*/
public function settings_radio( $field, $echo = true ) {
$field['type'] = 'radio'; //making sure type is set to radio
$selected_value = $this->get_setting( $field['name'], rgar( $field, 'default_value' ) );
$field_attributes = $this->get_field_attributes( $field );
$have_icon = $this->choices_have_icon( rgar( $field, 'choices' ) );
$horizontal = rgar( $field, 'horizontal' ) || $have_icon ? ' gaddon-setting-inline' : '';
$html = '';
if ( is_array( $field['choices'] ) ) {
foreach ( $field['choices'] as $i => $choice ) {
if ( rgempty( 'id', $choice ) ) {
$choice['id'] = $field['name'] . $i;
}
$choice_attributes = $this->get_choice_attributes( $choice, $field_attributes );
$tooltip = $this->maybe_get_tooltip( $choice );
$radio_value = isset( $choice['value'] ) ? $choice['value'] : $choice['label'];
$checked = checked( $selected_value, $radio_value, false );
if ( $have_icon ) {
/* Get the defined icon. */
$icon = rgar( $choice, 'icon' ) ? $choice['icon'] : 'fa-cog';
/* Set icon tag based on icon type. */
if ( filter_var( $icon, FILTER_VALIDATE_URL ) ) {
$icon_tag = '';
} else {
$icon_tag = '';
}
$html .= '
';
$html .= '';
$html .= '';
$html .= '
';
} else {
$html .= '
';
$html .= '';
$html .= '
';
}
}
}
if ( $this->field_failed_validation( $field ) ) {
$html .= $this->get_error_icon( $field );
}
if ( $echo ) {
echo $html;
}
return $html;
}
/**
* Determines if any of the available settings choices have an icon.
*
* @access public
* @param array $choices (default: array())
* @return bool
*/
public function choices_have_icon( $choices = array() ) {
$have_icon = false;
foreach ( $choices as $choice ) {
if ( rgar( $choice, 'icon' ) ) {
$have_icon = true;
}
}
return $have_icon;
}
/***
* Renders and initializes a drop down field based on the $field array
*
* @param array $field - Field array containing the configuration options of this field
* @param bool $echo = true - true to echo the output to the screen, false to simply return the contents as a string
*
* @return string The HTML for the field
*/
public function settings_select( $field, $echo = true ) {
$field['type'] = 'select'; // making sure type is set to select
$attributes = $this->get_field_attributes( $field );
$value = $this->get_setting( $field['name'], rgar( $field, 'default_value' ) );
$name = '' . esc_attr( $field['name'] );
// If no choices were provided and there is a no choices message, display it.
if ( ( empty( $field['choices'] ) || ! rgar( $field, 'choices' ) ) && rgar( $field, 'no_choices' ) ) {
$html = $field['no_choices'];
} else {
$html = sprintf(
'',
'_gaddon_setting_' . $name, implode( ' ', $attributes ), $this->get_select_options( $field['choices'], $value )
);
$html .= rgar( $field, 'after_select' );
}
if ( $this->field_failed_validation( $field ) ) {
$html .= $this->get_error_icon( $field );
}
if ( $echo ) {
echo $html;
}
return $html;
}
/**
* Renders and initializes a drop down field with a input field for custom input based on the $field array.
*
* @param array $field - Field array containing the configuration options of this field
* @param bool $echo = true - true to echo the output to the screen, false to simply return the contents as a string
*
* @return string The HTML for the field
*/
public function settings_select_custom( $field, $echo = true ) {
/* Prepare select field */
$select_field = $field;
$select_field_value = $this->get_setting( $select_field['name'], rgar( $select_field, 'default_value' ) );
$select_field['onchange'] = '';
$select_field['class'] = ( isset( $select_field['class'] ) ) ? $select_field['class'] . 'gaddon-setting-select-custom' : 'gaddon-setting-select-custom';
/* Prepare input field */
$input_field = $field;
$input_field['name'] .= '_custom';
$input_field['style'] = 'width:200px;max-width:90%;';
$input_field_display = '';
/* Loop through select choices and make sure option for custom exists */
$has_gf_custom = false;
foreach ( $select_field['choices'] as $choice ) {
if ( rgar( $choice, 'name' ) == 'gf_custom' || rgar( $choice, 'value' ) == 'gf_custom' ) {
$has_gf_custom = true;
}
/* If choice has choices, check inside those choices. */
if ( rgar( $choice, 'choices' ) ) {
foreach ( $choice['choices'] as $subchoice ) {
if ( rgar( $subchoice, 'name' ) == 'gf_custom' || rgar( $subchoice, 'value' ) == 'gf_custom' ) {
$has_gf_custom = true;
}
}
}
}
if ( ! $has_gf_custom ) {
$select_field['choices'][] = array(
'label' => esc_html__( 'Add Custom', 'gravityforms' ) .' ' . $select_field['label'],
'value' => 'gf_custom'
);
}
/* If select value is "gf_custom", hide the select field and display the input field. */
if ( $select_field_value == 'gf_custom' || ( count( $select_field['choices'] ) == 1 && $select_field['choices'][0]['value'] == 'gf_custom' ) ) {
$select_field['style'] = 'display:none;';
} else {
$input_field_display = ' style="display:none;"';
}
/* Add select field */
$html = $this->settings_select( $select_field, false );
/* Add input field */
$html .= '
';
// Get generic map limit.
$limit = empty( $field['limit'] ) ? 0 : $field['limit'];
// Initialize generic map via Javascript.
$html .= "
";
// If automatic display is enabled, echo field HTML.
if ( $echo ) {
echo $html;
}
return $html;
}
/**
* Renders and initializes a field map field based on the $field array whose choices are populated by the fields to be mapped.
*
* @since unknown
* @access public
*
* @uses GFAddOn::field_map_table_header()
* @uses GFAddOn::get_mapped_field_name()
* @uses GFAddOn::get_required_indicator()
* @uses GFAddOn::maybe_get_tooltip()
* @uses GFAddOn::setting_dependency_met()
* @uses GFAddOn::settings_field_map_select()
*
* @param array $field Field array containing the configuration options of this field.
* @param bool $echo Determines if field contents should automatically be displayed. Defaults to true.
*
* @return string The HTML for the field
*/
public function settings_field_map( $field, $echo = true ) {
// Initialize return HTML string.
$html = '';
// Get field map choices.
$field_map = rgar( $field, 'field_map' );
// If no field map choices exist, return HTML.
if ( empty( $field_map ) ) {
return $html;
}
// Get current form ID.
$form_id = rgget( 'id' );
// Display field map table header.
$html .= '
' .
$this->field_map_table_header() .
'';
// Loop through field map choices.
foreach ( $field['field_map'] as $child_field ) {
// If field map choice does not meet the dependencies required to be displayed, skip it.
if ( ! $this->setting_dependency_met( rgar( $child_field, 'dependency' ) ) ) {
continue;
}
// Get field map choice name, tooltip and required indicator.
$child_field['name'] = $this->get_mapped_field_name( $field, $child_field['name'] );
$tooltip = $this->maybe_get_tooltip( $child_field );
$required = rgar( $child_field, 'required' ) ? ' ' . $this->get_required_indicator( $child_field ) : '';
// Display field map choice row.
$html .= '
';
// Display hidden field containing dynamic field map value.
$html .= $this->settings_hidden( $field, false );
// Get dynamic field map limit.
$limit = empty( $field['limit'] ) ? 0 : $field['limit'];
// Initialize dynamic field map via Javascript.
$html .= "
";
// If automatic display is enabled, echo field HTML.
if ( $echo ) {
echo $html;
}
return $html;
}
/**
* Renders a field select field for field maps.
*
* @since unknown
* @access public
*
* @uses GFAddOn::get_field_map_choices()
* @uses GF_Field::get_form_editor_field_title()
*
* @param array $field Field array containing the configuration options of this field.
* @param int $form_id Form ID to retrieve fields from.
*
* @return string The HTML for the field
*/
public function settings_field_map_select( $field, $form_id ) {
// Get field types to only display.
$field_type = rgempty( 'field_type', $field ) ? null : $field['field_type'];
// Get field types to exclude.
$exclude_field_types = rgempty( 'exclude_field_types', $field ) ? null : $field['exclude_field_types'];
// Get form field choices based on field type inclusions/exclusions.
$field['choices'] = $this->get_field_map_choices( $form_id, $field_type, $exclude_field_types );
// If no choices were found, return error.
if ( empty( $field['choices'] ) || ( count( $field['choices'] ) == 1 && rgblank( $field['choices'][0]['value'] ) ) ) {
if ( ( ! is_array( $field_type ) && ! rgblank( $field_type ) ) || ( is_array( $field_type ) && count( $field_type ) == 1 ) ) {
$type = is_array( $field_type ) ? $field_type[0] : $field_type;
$type = ucfirst( GF_Fields::get( $type )->get_form_editor_field_title() );
return sprintf( __( 'Please add a %s field to your form.', 'gravityforms' ), $type );
}
}
// Set default value.
$field['default_value'] = $this->get_default_field_select_field( $field );
return $this->settings_select( $field, false );
}
/**
* Prepares the markup for mapping field key and value fields.
*
* @since 2.2
* @access public
*
* @uses GFAddOn::get_current_form()
* @uses GFAddOn::get_field_map_choices()
*
* @param string $type The field type being prepared; key or value.
* @param array $select_field The drop down field properties.
* @param array $text_field The text field properties.
*
* @return string
*/
public function get_mapping_field( $type, $select_field, $text_field ) {
// If use form fields as choices flag is set, add as choices.
if ( isset( $select_field['choices'] ) && ! is_array( $select_field['choices'] ) && 'form_fields' === strtolower( $select_field['choices'] ) ) {
// Set choices to form fields.
$select_field['choices'] = $this->get_field_map_choices( rgget( 'id' ) );
}
// If field has no choices, display custom field only.
if ( empty( $select_field['choices'] ) ) {
// Set field value to custom key.
$select_field['value'] = 'gf_custom';
// Display field row.
return sprintf(
'
%s
%s
',
$this->settings_hidden( $select_field, false ),
$type,
$this->settings_text( $text_field, false )
);
} else {
// Set initial additional classes.
$additional_classes = array();
// Set has custom key flag.
$has_gf_custom = false;
// Loop through key field choices.
foreach ( $select_field['choices'] as $choice ) {
// If choice name or value is the custom key, set custom key flag to true and exit loop.
if ( rgar( $choice, 'name' ) == 'gf_custom' || rgar( $choice, 'value' ) == 'gf_custom' ) {
$has_gf_custom = true;
break;
}
// If choice has sub-choices, check for custom key option.
if ( rgar( $choice, 'choices' ) ) {
// Loop through sub-choices.
foreach ( $choice['choices'] as $subchoice ) {
// If sub-choice name or value is the custom key, set custom key flag to true and exit loop.
if ( rgar( $subchoice, 'name' ) == 'gf_custom' || rgar( $subchoice, 'value' ) == 'gf_custom' ) {
$has_gf_custom = true;
break;
}
}
}
}
// If custom key option is not found and we're allowed to add it, add it.
if ( ! $has_gf_custom ) {
if ( $type == 'key' ) {
$enable_custom = rgars( $select_field, 'key_field/custom_value' ) ? (bool) $select_field['key_field']['custom_value'] : ! (bool) rgar( $select_field, 'disable_custom' );
$enable_custom = isset( $select_field['enable_custom_key'] ) ? (bool) $select_field['enable_custom_key'] : $enable_custom;
$label = esc_html__( 'Add Custom Key', 'gravityforms' );
} else {
// Add merge tag class.
if ( rgars( $select_field, 'value_field/merge_tags' ) ) {
$additional_classes[] = 'supports-merge-tags';
}
$enable_custom = rgars( $select_field, 'value_field/custom_value' ) ? (bool) $select_field['value_field']['custom_value'] : (bool) rgars( $select_field, 'enable_custom_value' );
$label = esc_html__( 'Add Custom Value', 'gravityforms' );
}
if ( $enable_custom ) {
$select_field['choices'][] = array(
'label' => $label,
'value' => 'gf_custom'
);
}
}
// Display field row.
return sprintf(
'
';
}
/**
* Heading for field map field column.
*
* @since 2.2
* @access public
*
* @used-by GFAddOn::field_map_table_header()
*
* @return string
*/
public function field_map_title() {
return esc_html__( 'Field', 'gravityforms' );
}
/**
* Get field map choices for specific form.
*
* @since unknown
* @access public
*
* @uses GFCommon::get_label()
* @uses GFFormsModel::get_entry_meta()
* @uses GFFormsModel::get_form_meta()
* @uses GF_Field::get_entry_inputs()
* @uses GF_Field::get_form_editor_field_title()
* @uses GF_Field::get_input_type()
*
* @param int $form_id Form ID to display fields for.
* @param array|string $field_type Field types to only include as choices. Defaults to null.
* @param array|string $exclude_field_types Field types to exclude from choices. Defaults to null.
*
* @return array
*/
public static function get_field_map_choices( $form_id, $field_type = null, $exclude_field_types = null ) {
$form = GFFormsModel::get_form_meta( $form_id );
$fields = array();
// Setup first choice
if ( rgblank( $field_type ) || ( is_array( $field_type ) && count( $field_type ) > 1 ) ) {
$first_choice_label = __( 'Select a Field', 'gravityforms' );
} else {
$type = is_array( $field_type ) ? $field_type[0] : $field_type;
$type = ucfirst( GF_Fields::get( $type )->get_form_editor_field_title() );
$first_choice_label = sprintf( __( 'Select a %s Field', 'gravityforms' ), $type );
}
$fields[] = array( 'value' => '', 'label' => $first_choice_label );
// if field types not restricted add the default fields and entry meta
if ( is_null( $field_type ) ) {
$fields[] = array( 'value' => 'id', 'label' => esc_html__( 'Entry ID', 'gravityforms' ) );
$fields[] = array( 'value' => 'date_created', 'label' => esc_html__( 'Entry Date', 'gravityforms' ) );
$fields[] = array( 'value' => 'ip', 'label' => esc_html__( 'User IP', 'gravityforms' ) );
$fields[] = array( 'value' => 'source_url', 'label' => esc_html__( 'Source Url', 'gravityforms' ) );
$fields[] = array( 'value' => 'form_title', 'label' => esc_html__( 'Form Title', 'gravityforms' ) );
$entry_meta = GFFormsModel::get_entry_meta( $form['id'] );
foreach ( $entry_meta as $meta_key => $meta ) {
$fields[] = array( 'value' => $meta_key, 'label' => rgars( $entry_meta, "{$meta_key}/label" ) );
}
}
// Populate form fields
if ( is_array( $form['fields'] ) ) {
foreach ( $form['fields'] as $field ) {
$input_type = $field->get_input_type();
$inputs = $field->get_entry_inputs();
$field_is_valid_type = ( empty( $field_type ) || ( is_array( $field_type ) && in_array( $input_type, $field_type ) ) || ( ! empty( $field_type ) && $input_type == $field_type ) );
if ( is_null( $exclude_field_types ) ) {
$exclude_field = false;
} elseif ( is_array( $exclude_field_types ) ) {
if ( in_array( $input_type, $exclude_field_types ) ) {
$exclude_field = true;
} else {
$exclude_field = false;
}
} else {
//not array, so should be single string
if ( $input_type == $exclude_field_types ) {
$exclude_field = true;
} else {
$exclude_field = false;
}
}
if ( is_array( $inputs ) && $field_is_valid_type && ! $exclude_field ) {
//If this is an address field, add full name to the list
if ( $input_type == 'address' ) {
$fields[] = array(
'value' => $field->id,
'label' => strip_tags( GFCommon::get_label( $field ) . ' (' . esc_html__( 'Full', 'gravityforms' ) . ')' )
);
}
//If this is a name field, add full name to the list
if ( $input_type == 'name' ) {
$fields[] = array(
'value' => $field->id,
'label' => strip_tags( GFCommon::get_label( $field ) . ' (' . esc_html__( 'Full', 'gravityforms' ) . ')' )
);
}
//If this is a checkbox field, add to the list
if ( $input_type == 'checkbox' ) {
$fields[] = array(
'value' => $field->id,
'label' => strip_tags( GFCommon::get_label( $field ) . ' (' . esc_html__( 'Selected', 'gravityforms' ) . ')' )
);
}
foreach ( $inputs as $input ) {
$fields[] = array(
'value' => $input['id'],
'label' => strip_tags( GFCommon::get_label( $field, $input['id'] ) )
);
}
} elseif ( $input_type == 'list' && $field->enableColumns && $field_is_valid_type && ! $exclude_field ) {
$fields[] = array(
'value' => $field->id,
'label' => strip_tags( GFCommon::get_label( $field ) . ' (' . esc_html__( 'Full', 'gravityforms' ) . ')' )
);
$col_index = 0;
foreach ( $field->choices as $column ) {
$fields[] = array(
'value' => $field->id . '.' . $col_index,
'label' => strip_tags( GFCommon::get_label( $field ) . ' (' . esc_html( rgar( $column, 'text' ) ) . ')' ),
);
$col_index ++;
}
} elseif ( ! $field->displayOnly && $field_is_valid_type && ! $exclude_field ) {
$fields[] = array( 'value' => $field->id, 'label' => strip_tags( GFCommon::get_label( $field ) ) );
}
}
}
/**
* Filter the choices available in the field map drop down.
*
* @since 2.0.7.11
*
* @param array $fields The value and label properties for each choice.
* @param int $form_id The ID of the form currently being configured.
* @param null|array $field_type Null or the field types to be included in the drop down.
* @param null|array|string $exclude_field_types Null or the field type(s) to be excluded from the drop down.
*/
$fields = apply_filters( 'gform_addon_field_map_choices', $fields, $form_id, $field_type, $exclude_field_types );
if ( function_exists( 'get_called_class' ) ) {
$callable = array( get_called_class(), 'get_instance' );
if ( is_callable( $callable ) ) {
$add_on = call_user_func( $callable );
$slug = $add_on->get_slug();
$fields = apply_filters( "gform_{$slug}_field_map_choices", $fields, $form_id, $field_type, $exclude_field_types );
}
}
return $fields;
}
/**
* Get input name for field map field.
*
* @since unknown
* @access public
*
* @used-by GFAddOn::settings_field_map()
* @used-by GFAddOn::validate_field_map_settings()
*
* @param array $parent_field Field map field.
* @param string $field_name Child field.
*
* @return string
*/
public function get_mapped_field_name( $parent_field, $field_name ) {
return "{$parent_field['name']}_{$field_name}";
}
/**
* Get mapped key/value pairs for standard field map.
*
* @since unknown
* @access public
*
* @param array $feed Feed object.
* @param string $field_name Field map field name.
*
* @return array
*/
public static function get_field_map_fields( $feed, $field_name ) {
// Initialize return fields array.
$fields = array();
// Get prefix for mapped field map keys.
$prefix = "{$field_name}_";
// Loop through feed meta.
foreach ( $feed['meta'] as $name => $value ) {
// If field name matches prefix, add value to return array.
if ( strpos( $name, $prefix ) === 0 ) {
$name = str_replace( $prefix, '', $name );
$fields[ $name ] = $value;
}
}
return $fields;
}
/**
* Get mapped key/value pairs for dynamic field map.
*
* @since 1.9.9.9
* @access public
*
* @param array $feed Feed object.
* @param string $field_name Dynamic field map field name.
*
* @return array
*/
public static function get_dynamic_field_map_fields( $feed, $field_name ) {
// Initialize return fields array.
$fields = array();
// Get dynamic field map field.
$dynamic_fields = rgars( $feed, 'meta/' . $field_name );
// If dynamic field map field is found, loop through mapped fields and add to array.
if ( ! empty( $dynamic_fields ) ) {
// Loop through mapped fields.
foreach ( $dynamic_fields as $dynamic_field ) {
// Get mapped key or replace with custom value.
$field_key = 'gf_custom' === $dynamic_field['key'] ? $dynamic_field['custom_key'] : $dynamic_field['key'];
// Add mapped field to return array.
$fields[ $field_key ] = $dynamic_field['value'];
}
}
return $fields;
}
/**
* Get mapped key/value pairs for generic map.
*
* @since 2.2
* @access public
*
* @param array $feed Feed object or settings array.
* @param string $field_name Generic map field name.
* @param array $form Form object. Defaults to empty array.
* @param array $entry Entry object. Defaults to empty array.
*
* @uses GFCommon::replace_variables()
*
* @return array
*/
public function get_generic_map_fields( $feed, $field_name, $form = array(), $entry = array() ) {
// Initialize return fields array.
$fields = array();
// Get generic map field.
$generic_fields = rgar( $feed, 'meta' ) ? rgars( $feed, 'meta/' . $field_name ) : rgar( $feed, $field_name );
// If generic map field is found, loop through mapped fields and add to array.
if ( ! empty( $generic_fields ) ) {
// Loop through mapped fields.
foreach ( $generic_fields as $generic_field ) {
// Get mapped key or replace with custom value.
$field_key = 'gf_custom' === $generic_field['key'] ? $generic_field['custom_key'] : $generic_field['key'];
// Get mapped field choice or replace with custom value.
if ( 'gf_custom' === $generic_field['value'] ) {
// If form isn't set, use custom value. Otherwise, replace merge tags.
$field_value = empty( $form ) ? $generic_field['custom_value'] : GFCommon::replace_variables( $generic_field['custom_value'], $form, $entry, false, false, false, 'text' );
} else {
// If form isn't set, use value. Otherwise, get field value.
$field_value = empty( $form ) ? $generic_field['value'] : $this->get_field_value( $form, $entry, $generic_field['value'] );
}
// Add mapped field to return array.
$fields[ $field_key ] = $field_value;
}
}
return $fields;
}
//------------ Field Select Field Type ------------------------
/**
* Renders and initializes a drop down field based on the $field array whose choices are populated by the form's fields.
*
* @param array $field - Field array containing the configuration options of this field
* @param bool $echo = true - true to echo the output to the screen, false to simply return the contents as a string
*
* @return string The HTML for the field
*/
public function settings_field_select( $field, $echo = true ) {
$field = $this->prepare_field_select_field( $field );
$html = $this->settings_select( $field, false );
if ( $echo ) {
echo $html;
}
return $html;
}
public function prepare_field_select_field( $field ) {
$args = is_array( rgar( $field, 'args' ) ) ? rgar( $field, 'args' ) : array( rgar( $field, 'args' ) );
$args = wp_parse_args(
$args, array(
'append_choices' => array(),
'disable_first_choice' => false,
)
);
$field['choices'] = array();
if ( ! $args['disable_first_choice'] ) {
// Setup first choice
if ( empty( $args['input_types'] ) || ( is_array( $args['input_types'] ) && count( $args['input_types'] ) > 1 ) ) {
$first_choice_label = __( 'Select a Field', 'gravityforms' );
} else {
$type = is_array( $args['input_types'] ) ? $args['input_types'][0] : $args['input_types'];
$type = ucfirst( GF_Fields::get( $type )->get_form_editor_field_title() );
$first_choice_label = sprintf( __( 'Select a %s Field', 'gravityforms' ), $type );
}
$field['choices'][] = array( 'value' => '', 'label' => $first_choice_label );
}
$field['choices'] = array_merge( $field['choices'], $this->get_form_fields_as_choices( $this->get_current_form(), $args ) );
if ( ! empty( $args['append_choices'] ) ) {
$field['choices'] = array_merge( $field['choices'], $args['append_choices'] );
}
// Set default value.
$field['default_value'] = $this->get_default_field_select_field( $field );
return $field;
}
/**
* Returns the field to be selected by default for field select fields based on matching labels.
*
* @access public
* @param array $field - Field array containing the configuration options of this field
*
* @return string|null
*/
public function get_default_field_select_field( $field ) {
// Prepare field name.
$field_name = str_replace( '.', '_', $field['name'] );
// If field's value is already set, return it.
if ( $this->get_setting( $field_name ) ) {
return $this->get_setting( $field_name );
}
// If field's default value is not an array and not empty, return it.
if ( ! rgempty( 'default_value', $field ) && ! is_array( $field['default_value'] ) ) {
return $field['default_value'];
}
// Set default value if auto populate is not disabled.
if ( rgar( $field, 'auto_mapping' ) !== false ) {
$field_label = rgar( $field, 'label' );
// Initialize array to store auto-population choices.
$default_value_choices = array( $field_label );
// Define global aliases to help with the common case mappings.
$global_aliases = array(
__('First Name', 'gravityforms') => array( __( 'Name (First)', 'gravityforms' ) ),
__('Last Name', 'gravityforms') => array( __( 'Name (Last)', 'gravityforms' ) ),
__('Address', 'gravityforms') => array( __( 'Address (Street Address)', 'gravityforms' ) ),
__('Address 2', 'gravityforms') => array( __( 'Address (Address Line 2)', 'gravityforms' ) ),
__('City', 'gravityforms') => array( __( 'Address (City)', 'gravityforms' ) ),
__('State', 'gravityforms') => array( __( 'Address (State / Province)', 'gravityforms' ) ),
__('Zip', 'gravityforms') => array( __( 'Address (Zip / Postal Code)', 'gravityforms' ) ),
__('Country', 'gravityforms') => array( __( 'Address (Country)', 'gravityforms' ) ),
);
// If one or more global aliases are defined for this particular field label, merge them into auto-population choices.
if ( isset( $global_aliases[ $field_label ] ) ){
$default_value_choices = array_merge( $default_value_choices, $global_aliases[ $field_label ] );
}
// If field aliases are defined, merge them into auto-population choices.
if ( rgars( $field, 'default_value/aliases' ) ) {
$default_value_choices = array_merge( $default_value_choices, $field['default_value']['aliases'] );
}
// Convert all auto-population choices to lowercase.
$default_value_choices = array_map( 'strtolower', $default_value_choices );
// Loop through fields.
foreach ( $field['choices'] as $choice ) {
// If choice value is empty, skip it.
if ( rgblank( $choice['value'] ) ) {
continue;
}
// If lowercase field label matches a default value choice, set it to the default value.
if ( in_array( strtolower( $choice['label'] ), $default_value_choices ) ) {
return $choice['value'];
}
}
}
return null;
}
/**
* Retrieve an array of form fields formatted for select, radio and checkbox settings fields.
*
* @access public
* @param array $form - The form object
* @param array $args - Additional settings to check for (field and input types to include, callback for applicable input type)
*
* @return array The array of formatted form fields
*/
public function get_form_fields_as_choices( $form, $args = array() ) {
$fields = array();
if ( ! is_array( $form['fields'] ) ) {
return $fields;
}
$args = wp_parse_args(
$args, array(
'field_types' => array(),
'input_types' => array(),
'callback' => false
)
);
foreach ( $form['fields'] as $field ) {
if ( ! empty( $args['field_types'] ) && ! in_array( $field->type, $args['field_types'] ) ) {
continue;
}
$input_type = GFFormsModel::get_input_type( $field );
$is_applicable_input_type = empty( $args['input_types'] ) || in_array( $input_type, $args['input_types'] );
if ( is_callable( $args['callback'] ) ) {
$is_applicable_input_type = call_user_func( $args['callback'], $is_applicable_input_type, $field, $form );
}
if ( ! $is_applicable_input_type ) {
continue;
}
if ( ! empty( $args['property'] ) && ( ! isset( $field->{$args['property']} ) || $field->{$args['property']} != $args['property_value'] ) ) {
continue;
}
$inputs = $field->get_entry_inputs();
if ( is_array( $inputs ) ) {
// if this is an address field, add full name to the list
if ( $input_type == 'address' ) {
$fields[] = array(
'value' => $field->id,
'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Full', 'gravityforms' ) . ')'
);
}
// if this is a name field, add full name to the list
if ( $input_type == 'name' ) {
$fields[] = array(
'value' => $field->id,
'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Full', 'gravityforms' ) . ')'
);
}
// if this is a checkbox field, add to the list
if ( $input_type == 'checkbox' ) {
$fields[] = array(
'value' => $field->id,
'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Selected', 'gravityforms' ) . ')'
);
}
foreach ( $inputs as $input ) {
$fields[] = array(
'value' => $input['id'],
'label' => GFCommon::get_label( $field, $input['id'] )
);
}
} elseif ( $input_type == 'list' && $field->enableColumns ) {
$fields[] = array(
'value' => $field->id,
'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Full', 'gravityforms' ) . ')'
);
$col_index = 0;
foreach ( $field->choices as $column ) {
$fields[] = array(
'value' => $field->id . '.' . $col_index,
'label' => GFCommon::get_label( $field ) . ' (' . rgar( $column, 'text' ) . ')',
);
$col_index ++;
}
} elseif ( ! $field->displayOnly ) {
$fields[] = array( 'value' => $field->id, 'label' => GFCommon::get_label( $field ) );
} else {
$fields[] = array(
'value' => $field->id,
'label' => GFCommon::get_label( $field )
);
}
}
return $fields;
}
/**
* Renders and initializes a checkbox field that displays a select field when checked based on the $field array.
*
* @access public
* @param array $field - Field array containing the configuration options of this field
* @param bool $echo = true - true to echo the output to the screen, false to simply return the contents as a string
*
* @return string The HTML for the field
*/
public function settings_checkbox_and_select( $field, $echo = true ) {
$field = $this->prepare_settings_checkbox_and_select( $field );
$checkbox_field = $field['checkbox'];
$select_field = $field['select'];
$is_enabled = $this->get_setting( $checkbox_field['name'] );
// get markup
$html = sprintf(
'%s %s %s',
$this->settings_checkbox( $checkbox_field, false ),
$select_field['name'] . 'Span',
$is_enabled ? '' : 'gf_invisible',
$this->settings_select( $select_field, false ),
$this->maybe_get_tooltip( $select_field )
);
if ( $echo ) {
echo $html;
}
return $html;
}
public function prepare_settings_checkbox_and_select( $field ) {
// prepare checkbox
$checkbox_input = rgars( $field, 'checkbox' );
$checkbox_field = array(
'type' => 'checkbox',
'name' => $field['name'] . 'Enable',
'label' => esc_html__( 'Enable', 'gravityforms' ),
'horizontal' => true,
'value' => '1',
'choices' => false,
'tooltip' => false
);
$checkbox_field = wp_parse_args( $checkbox_input, $checkbox_field );
// prepare select
$select_input = rgars( $field, 'select' );
$select_field = array(
'name' => $field['name'] . 'Value',
'type' => 'select',
'class' => '',
'tooltip' => false
);
$select_field['class'] .= ' ' . $select_field['name'];
$select_field = wp_parse_args( $select_input, $select_field );
// a little more with the checkbox
if( empty( $checkbox_field['choices'] ) ) {
$checkbox_field['choices'] = array(
array(
'name' => $checkbox_field['name'],
'label' => $checkbox_field['label'],
'onchange' => sprintf( "( function( $, elem ) {
$( elem ).parents( 'td' ).css( 'position', 'relative' );
if( $( elem ).prop( 'checked' ) ) {
$( '%1\$s' ).css( 'visibility', 'visible' );
$( '%1\$s' ).fadeTo( 400, 1 );
} else {
$( '%1\$s' ).fadeTo( 400, 0, function(){
$( '%1\$s' ).css( 'visibility', 'hidden' );
} );
}
} )( jQuery, this );",
"#{$select_field['name']}Span" )
)
);
}
$field['select'] = $select_field;
$field['checkbox'] = $checkbox_field;
return $field;
}
/***
* Renders the save button for settings pages
*
* @param array $field - Field array containing the configuration options of this field
* @param bool $echo = true - true to echo the output to the screen, false to simply return the contents as a string
*
* @return string The HTML
*/
public function settings_save( $field, $echo = true ) {
$field['type'] = 'submit';
$field['name'] = 'gform-settings-save';
$field['class'] = 'button-primary gfbutton';
if ( ! rgar( $field, 'value' ) ) {
$field['value'] = esc_html__( 'Update Settings', 'gravityforms' );
}
$attributes = $this->get_field_attributes( $field );
$html = '';
if ( $echo ) {
echo $html;
}
return $html;
}
/**
* Parses the properties of the $field meta array and returns a set of HTML attributes to be added to the HTML element.
*
* @param array $field - current field meta to be parsed.
* @param array $default - default set of properties. Will be appended to the properties specified in the $field array
*
* @return array - resulting HTML attributes ready to be included in the HTML element.
*/
public function get_field_attributes( $field, $default = array() ) {
/**
* Each nonstandard property will be extracted from the $props array so it is not auto-output in the field HTML
*
* @param array $field The current field meta to be parsed
*/
$no_output_props = apply_filters(
'gaddon_no_output_field_properties',
array(
'default_value', 'label', 'choices', 'feedback_callback', 'checked', 'checkbox_label', 'value', 'type',
'validation_callback', 'required', 'hidden', 'tooltip', 'dependency', 'messages', 'name', 'args',
'exclude_field_types', 'field_type', 'after_input', 'input_type', 'icon', 'save_callback',
'enable_custom_value', 'enable_custom_key', 'merge_tags', 'key_field', 'value_field', 'callback',
), $field
);
$default_props = array(
'class' => '', // will default to gaddon-setting
'default_value' => '', // default value that should be selected or entered for the field
);
// Property switch case
switch ( $field['type'] ) {
case 'select':
$default_props['choices'] = array();
break;
case 'checkbox':
$default_props['checked'] = false;
$default_props['checkbox_label'] = '';
$default_props['choices'] = array();
break;
case 'text':
default:
break;
}
$props = wp_parse_args( $field, $default_props );
$props['id'] = rgempty( 'id', $props ) ? rgar( $props, 'name' ) : rgar( $props, 'id' );
$props['class'] = trim( "{$props['class']} gaddon-setting gaddon-{$props['type']}" );
// extract no-output properties from $props array so they are not auto-output in the field HTML
foreach ( $no_output_props as $prop ) {
if ( isset( $props[ $prop ] ) ) {
${$prop} = $props[ $prop ];
unset( $props[ $prop ] );
}
}
//adding default attributes
foreach ( $default as $key => $value ) {
if ( isset( $props[ $key ] ) ) {
$props[ $key ] = $value . $props[ $key ];
} else {
$props[ $key ] = $value;
}
}
// get an array of property strings, example: name='myFieldName'
$prop_strings = array();
foreach ( $props as $prop => $value ) {
$prop_strings[ $prop ] = "{$prop}='" . esc_attr( $value ) . "'";
}
return $prop_strings;
}
/**
* Parses the properties of the $choice meta array and returns a set of HTML attributes to be added to the HTML element.
*
* @param array $choice - current choice meta to be parsed.
* @param array $field_attributes - current field's attributes.
*
* @return array - resulting HTML attributes ready to be included in the HTML element.
*/
public function get_choice_attributes( $choice, $field_attributes, $default_choice_attributes = array() ) {
$choice_attributes = $field_attributes;
foreach ( $choice as $prop => $val ) {
$no_output_choice_attributes = array(
'default_value', 'label', 'checked', 'value', 'type',
'validation_callback', 'required', 'tooltip',
);
if ( in_array( $prop, $no_output_choice_attributes ) || is_array( $val ) ) {
unset( $choice_attributes[ $prop ] );
} else {
$choice_attributes[ $prop ] = "{$prop}='" . esc_attr( $val ) . "'";
}
}
//Adding default attributes. Either creating a new attribute or pre-pending to an existing one.
foreach ( $default_choice_attributes as $default_attr_name => $default_attr_value ) {
if ( isset( $choice_attributes[ $default_attr_name ] ) ) {
$choice_attributes[ $default_attr_name ] = $this->prepend_attribute( $default_attr_name, $default_attr_value, $choice_attributes[ $default_attr_name ] );
}
else {
$choice_attributes[ $default_attr_name ] = "{$default_attr_name}='" . esc_attr( $default_attr_value ) . "'";
}
}
return $choice_attributes;
}
/***
* @param $name - The name of the attribute to be added
* @param $attribute - The attribute value to be added
* @param $current_attribute - The full string containing the current attribute value
* @return mixed - The new attribute string with the new value added to the beginning of the list
*/
public function prepend_attribute( $name, $attribute, $current_attribute ) {
return str_replace( "{$name}='", "{$name}='{$attribute}", $current_attribute );
}
/**
* Validates settings fields.
* Validates that all fields are valid. Fields can be invalid when they are blank and marked as required or if it fails a custom validation check.
* To specify a custom validation, use the 'validation_callback' field meta property and implement the validation function with the custom logic.
*
* @param $fields - A list of all fields from the field meta configuration
* @param $settings - A list of submitted settings values
*
* @return bool - Returns true if all fields have passed validation, and false otherwise.
*/
public function validate_settings( $fields, $settings ) {
foreach ( $fields as $section ) {
if ( ! $this->setting_dependency_met( rgar( $section, 'dependency' ) ) ) {
continue;
}
foreach ( $section['fields'] as $field ) {
if ( ! $this->setting_dependency_met( rgar( $field, 'dependency' ) ) ) {
continue;
}
$field_setting = rgar( $settings, rgar( $field, 'name' ) );
if ( is_callable( rgar( $field, 'validation_callback' ) ) ) {
call_user_func( rgar( $field, 'validation_callback' ), $field, $field_setting );
continue;
}
if ( is_callable( array( $this, 'validate_' . $field['type'] . '_settings' ) ) ) {
call_user_func( array( $this, 'validate_' . $field['type'] . '_settings' ), $field, $settings );
continue;
}
if ( rgar( $field, 'required' ) && rgblank( $field_setting ) ) {
$this->set_field_error( $field, rgar( $field, 'error_message' ) );
}
}
}
$field_errors = $this->get_field_errors();
$is_valid = empty( $field_errors );
return $is_valid;
}
public function validate_text_settings( $field, $settings ) {
$field_setting = rgar( $settings, rgar( $field, 'name' ) );
if ( rgar( $field, 'required' ) && rgblank( $field_setting ) ) {
$this->set_field_error( $field, rgar( $field, 'error_message' ) );
}
$field_setting_safe = sanitize_text_field( $field_setting );
if ( $field_setting !== $field_setting_safe ) {
$message = esc_html__( 'The text you have entered is not valid. For security reasons, some characters are not allowed. ', 'gravityforms' );
$script = sprintf( 'jQuery("input[name=\"_gaddon_setting_%s\"]").val(jQuery(this).data("safe"));', $field['name'] );
$double_encoded_safe_value = htmlspecialchars( htmlspecialchars( $field_setting_safe, ENT_QUOTES ), ENT_QUOTES );
$message .= sprintf( " %s", htmlspecialchars( $script, ENT_QUOTES ), $double_encoded_safe_value, esc_html__('Fix it', 'gravityforms' ) );
$this->set_field_error( $field, $message );
}
}
public function validate_textarea_settings( $field, $settings ) {
$field_setting = rgar( $settings, rgar( $field, 'name' ) );
if ( rgar( $field, 'required' ) && rgblank( $field_setting ) ) {
$this->set_field_error( $field, rgar( $field, 'error_message' ) );
}
$field_setting_safe = $this->maybe_wp_kses( $field_setting );
if ( $field_setting !== $field_setting_safe ) {
$message = esc_html__( 'The text you have entered is not valid. For security reasons, some characters are not allowed. ', 'gravityforms' );
$script = sprintf( 'jQuery("textarea[name=\"_gaddon_setting_%s\"]").val(jQuery(this).data("safe"));', $field['name'] );
$double_encoded_safe_value = htmlspecialchars( htmlspecialchars( $field_setting_safe, ENT_QUOTES ), ENT_QUOTES );
$message .= sprintf( " %s", htmlspecialchars( $script, ENT_QUOTES ), $double_encoded_safe_value, esc_html__('Fix it', 'gravityforms' ) );
$this->set_field_error( $field, $message );
}
}
public function validate_radio_settings( $field, $settings ) {
$field_setting = rgar( $settings, rgar( $field, 'name' ) );
if ( rgar( $field, 'required' ) && rgblank( $field_setting ) ) {
$this->set_field_error( $field, rgar( $field, 'error_message' ) );
return;
}
if ( rgblank( $field_setting ) ){
return; //Nothing is selected. Let it pass validation
}
foreach( $field['choices'] as $choice ) {
if ( $this->is_choice_valid( $choice, $field_setting ) ) {
return; // Choice is valid
}
}
$this->set_field_error( $field, esc_html__( 'Invalid value', 'gravityforms' ) );
}
public function validate_select_settings( $field, $settings ) {
$field_name = str_replace( '[]', '', $field['name'] );
$field_setting = rgar( $settings, $field_name );
$multiple = rgar( $field, 'multiple' ) == 'multiple';
$required = rgar( $field, 'required' );
if ( ! $multiple && $required && rgblank( $field_setting ) ) {
$this->set_field_error( $field, rgar( $field, 'error_message' ) );
return;
}
if ( rgblank( $field_setting ) ) {
return;
}
if ( $multiple ) {
$selected = 0;
foreach( $field['choices'] as $choice ) {
if ( isset( $choice['choices'] ) ) {
foreach( $choice['choices'] as $optgroup_choice ) {
if ( $this->is_choice_valid( $optgroup_choice, $field_setting ) ) {
$selected++;
}
}
} else {
if ( $this->is_choice_valid( $choice, $field_setting ) ) {
$selected++;
}
}
}
if ( $required && $selected == 0 ) {
$this->set_field_error( $field, rgar( $field, 'error_message' ) );
return;
}
if ( ! $required && $selected !== count( $field_setting ) ) {
$this->set_field_error( $field, esc_html__( 'Invalid value', 'gravityforms' ) );
}
} else {
foreach( $field['choices'] as $choice ) {
if ( isset( $choice['choices'] ) ) {
foreach( $choice['choices'] as $optgroup_choice ) {
if ( $this->is_choice_valid( $optgroup_choice, $field_setting ) ) {
return;
}
}
} else {
if ( $this->is_choice_valid( $choice, $field_setting ) ) {
return; // Choice is valid
}
}
}
$this->set_field_error( $field, esc_html__( 'Invalid value', 'gravityforms' ) );
}
}
public function validate_checkbox_settings( $field, $settings ) {
if ( ! is_array( rgar( $field, 'choices' ) ) ) {
return;
}
$selected = 0;
foreach ( $field['choices'] as $choice ) {
$value = $this->get_setting( $choice['name'], '', $settings );
if ( ! in_array( $value, array( '1', '0' ) ) ) {
$this->set_field_error( $field, esc_html__( 'Invalid value', 'gravityforms' ) );
return;
}
if ( $value === '1' ) {
$selected++;
}
}
if ( rgar( $field, 'required' ) && $selected < 1 ) {
$this->set_field_error( $field, rgar( $field, 'error_message' ) );
}
}
public function validate_select_custom_settings( $field, $settings ) {
if ( ! is_array( rgar( $field, 'choices' ) ) ) {
return;
}
$select_value = rgar( $settings, $field['name'] );
$custom_value = rgar( $settings, $field['name'] . '_custom' );
if ( rgar( $field, 'required' ) && rgblank( $select_value ) ) {
$this->set_field_error( $field );
return;
}
if ( rgar( $field, 'required' ) && $select_value == 'gf_custom' && rgblank( $custom_value ) ) {
$custom_field = $field;
$custom_field['name'] .= '_custom';
$this->set_field_error( $custom_field );
return;
}
if ( $select_value != 'gf_custom' ) {
foreach( $field['choices'] as $choice ) {
if ( isset( $choice['choices'] ) ) {
foreach ( $choice['choices'] as $optgroup_choice ) {
if ( $this->is_choice_valid( $optgroup_choice, $select_value ) ) {
return;
}
}
} else {
if ( $this->is_choice_valid( $choice, $select_value ) ) {
return;
}
}
}
$this->set_field_error( $field, esc_html__( 'Invalid value', 'gravityforms' ) );
}
}
public function validate_field_select_settings( $field, $settings ) {
$field = $this->prepare_field_select_field( $field );
$this->validate_select_settings( $field, $settings );
}
public function validate_field_map_settings( $field, $settings ) {
$field_map = rgar( $field, 'field_map' );
if ( empty( $field_map ) ) {
return;
}
foreach ( $field_map as $child_field ) {
if ( ! $this->setting_dependency_met( rgar( $child_field, 'dependency' ) ) ) {
continue;
}
$child_field['name'] = $this->get_mapped_field_name( $field, $child_field['name'] );
$setting_value = rgar( $settings, $child_field['name'] );
if ( rgar( $child_field, 'required' ) && rgblank( $setting_value ) ) {
$this->set_field_error( $child_field );
} elseif ( rgar( $child_field, 'validation_callback' ) && is_callable( rgar( $child_field, 'validation_callback' ) ) ) {
call_user_func( rgar( $child_field, 'validation_callback' ), $child_field, $field );
}
}
}
public function validate_checkbox_and_select_settings( $field, $settings ) {
$field = $this->prepare_settings_checkbox_and_select( $field );
$checkbox_field = $field['checkbox'];
$select_field = $field['select'];
$this->validate_checkbox_settings( $checkbox_field, $settings );
$this->validate_select_settings( $select_field, $settings );
}
/**
* Helper to determine if the current choice is a match for the submitted field value.
*
* @param array $choice The choice properties.
* @param string|array $value The submitted field value.
*
* @return bool
*/
public function is_choice_valid( $choice, $value ) {
$choice_value = isset( $choice['value'] ) ? $choice['value'] : $choice['label'];
return is_array( $value ) ? in_array( $choice_value, $value ) : $choice_value == $value;
}
/**
* Sets the validation error message
* Sets the error message to be displayed when a field fails validation.
* When implementing a custom validation callback function, use this function to specify the error message to be displayed.
*
* @param array $field - The current field meta
* @param string $error_message - The error message to be displayed
*/
public function set_field_error( $field, $error_message = '' ) {
// set default error message if none passed
if ( ! $error_message ) {
$error_message = esc_html__( 'This field is required.', 'gravityforms' );
}
$this->_setting_field_errors[ $field['name'] ] = $error_message;
}
/**
* Gets the validation errors for a field.
* Returns validation errors associated with the specified field or a list of all validation messages (if a field isn't specified)
*
* @param array|boolean $field - Optional. The field meta. When specified, errors for this field will be returned
*
* @return mixed - If a field is specified, a string containing the error message will be returned. Otherwise, an array of all errors will be returned
*/
public function get_field_errors( $field = false ) {
if ( ! $field ) {
return $this->_setting_field_errors;
}
return isset( $this->_setting_field_errors[ $field['name'] ] ) ? $this->_setting_field_errors[ $field['name'] ] : array();
}
/**
* Gets the invalid field icon
* Returns the markup for an alert icon to indicate and highlight invalid fields.
*
* @param array $field - The field meta.
*
* @return string - The full markup for the icon
*/
public function get_error_icon( $field ) {
$error = $this->get_field_errors( $field );
return '';
}
/**
* Returns the tooltip markup if a tooltip is configured for the supplied item (field/child field/choice).
*
* @param array $item The item properties.
*
* @return string
*/
public function maybe_get_tooltip( $item ) {
$html = '';
if ( isset( $item['tooltip'] ) ) {
$html = ' ' . gform_tooltip( $item['tooltip'], rgar( $item, 'tooltip_class' ), true );
}
return $html;
}
/**
* Gets the required indicator
* Gets the markup of the required indicator symbol to highlight fields that are required
*
* @param $field - The field meta.
*
* @return string - Returns markup of the required indicator symbol
*/
public function get_required_indicator( $field ) {
return '*';
}
/**
* Checks if the specified field failed validation
*
* @param $field - The field meta to be checked
*
* @return bool|mixed - Returns a validation error string if the field has failed validation. Otherwise returns false
*/
public function field_failed_validation( $field ) {
$field_error = $this->get_field_errors( $field );
return ! empty( $field_error ) ? $field_error : false;
}
/**
* Filter settings fields.
* Runs through each field and applies the 'save_callback', if set, before saving the settings.
* To specify a custom save filter, use the 'save_callback' field meta property and implement the save filter function with the custom logic.
*
* @param $fields - A list of all fields from the field meta configuration
* @param $settings - A list of submitted settings values
*
* @return $settings - The updated settings values.
*/
public function filter_settings( $fields, $settings ) {
foreach ( $fields as $section ) {
if ( ! $this->setting_dependency_met( rgar( $section, 'dependency' ) ) ) {
continue;
}
foreach ( $section['fields'] as $field ) {
if ( ! $this->setting_dependency_met( rgar( $field, 'dependency' ) ) ) {
continue;
}
$field_setting = rgar( $settings, rgar( $field, 'name' ) );
if ( is_callable( rgar( $field, 'save_callback' ) ) ) {
$settings[ $field['name'] ] = call_user_func( rgar( $field, 'save_callback' ), $field, $field_setting );
continue;
}
}
}
return $settings;
}
public function add_field_before( $name, $fields, $settings ) {
return $this->add_field( $name, $fields, $settings, 'before' );
}
public function add_field_after( $name, $fields, $settings ) {
return $this->add_field( $name, $fields, $settings, 'after' );
}
public function add_field( $name, $fields, $settings, $pos ) {
if ( rgar( $fields, 'name' ) ) {
$fields = array( $fields );
}
$pos_mod = $pos == 'before' ? 0 : 1;
foreach ( $settings as &$section ) {
for ( $i = 0; $i < count( $section['fields'] ); $i ++ ) {
if ( $section['fields'][ $i ]['name'] == $name ) {
array_splice( $section['fields'], $i + $pos_mod, 0, $fields );
break 2;
}
}
}
return $settings;
}
public function remove_field( $name, $settings ) {
foreach ( $settings as &$section ) {
for ( $i = 0; $i < count( $section['fields'] ); $i ++ ) {
if ( $section['fields'][ $i ]['name'] == $name ) {
array_splice( $section['fields'], $i, 1 );
break 2;
}
}
}
return $settings;
}
public function replace_field( $name, $fields, $settings ) {
if ( rgar( $fields, 'name' ) ) {
$fields = array( $fields );
}
foreach ( $settings as &$section ) {
for ( $i = 0; $i < count( $section['fields'] ); $i ++ ) {
if ( $section['fields'][ $i ]['name'] == $name ) {
array_splice( $section['fields'], $i, 1, $fields );
break 2;
}
}
}
return $settings;
}
public function get_field( $name, $settings ) {
foreach ( $settings as $section ) {
for ( $i = 0; $i < count( $section['fields'] ); $i ++ ) {
if ( rgar( $section['fields'][ $i ], 'name' ) == $name ) {
return $section['fields'][ $i ];
}
}
}
return false;
}
public function build_choices( $key_value_pairs ) {
$choices = array();
if ( ! is_array( $key_value_pairs ) ) {
return $choices;
}
$first_key = key( $key_value_pairs );
$is_numeric = is_int( $first_key ) && $first_key === 0;
foreach ( $key_value_pairs as $value => $label ) {
if ( $is_numeric ) {
$value = $label;
}
$choices[] = array( 'value' => $value, 'label' => $label );
}
return $choices;
}
//-------------- Simple Condition ------------------------------------------------
/**
* Helper to create a simple conditional logic set of fields. It creates one row of conditional logic with Field/Operator/Value inputs.
*
* @param mixed $setting_name_root - The root name to be used for inputs. It will be used as a prefix to the inputs that make up the conditional logic fields.
*
* @return string The HTML
*/
public function simple_condition( $setting_name_root ) {
$conditional_fields = $this->get_conditional_logic_fields();
$value_input = esc_js( '_gaddon_setting_' . esc_attr( $setting_name_root ) . '_value' );
$object_type = esc_js( "simple_condition_{$setting_name_root}" );
$str = $this->settings_select( array(
'name' => "{$setting_name_root}_field_id",
'type' => 'select',
'choices' => $conditional_fields,
'class' => 'optin_select',
'onchange' => "jQuery('#" . esc_js( $setting_name_root ) . "_container').html(GetRuleValues('{$object_type}', 0, jQuery(this).val(), '', '{$value_input}'));"
), false );
$str .= $this->settings_select( array(
'name' => "{$setting_name_root}_operator",
'type' => 'select',
'onchange' => "SetRuleProperty('{$object_type}', 0, 'operator', jQuery(this).val()); jQuery('#" . esc_js( $setting_name_root ) . "_container').html(GetRuleValues('{$object_type}', 0, jQuery('#{$setting_name_root}_field_id').val(), '', '{$value_input}'));",
'choices' => array(
array(
'value' => 'is',
'label' => esc_html__( 'is', 'gravityforms' ),
),
array(
'value' => 'isnot',
'label' => esc_html__( 'is not', 'gravityforms' ),
),
array(
'value' => '>',
'label' => esc_html__( 'greater than', 'gravityforms' ),
),
array(
'value' => '<',
'label' => esc_html__( 'less than', 'gravityforms' ),
),
array(
'value' => 'contains',
'label' => esc_html__( 'contains', 'gravityforms' ),
),
array(
'value' => 'starts_with',
'label' => esc_html__( 'starts with', 'gravityforms' ),
),
array(
'value' => 'ends_with',
'label' => esc_html__( 'ends with', 'gravityforms' ),
),
),
), false );
$str .= sprintf( "", esc_attr( $setting_name_root ) );
$field_id = $this->get_setting( "{$setting_name_root}_field_id" );
$value = $this->get_setting( "{$setting_name_root}_value" );
$operator = $this->get_setting( "{$setting_name_root}_operator" );
if ( empty( $operator ) ) {
$operator = 'is';
}
$field_id_attribute = ! empty( $field_id ) ? $field_id : 'jQuery("#' . esc_attr( $setting_name_root ) . '_field_id").val()';
$str .= "";
return $str;
}
/**
* Override this to define the array of choices which should be used to populate the Simple Condition fields drop down.
*
* Each choice should have 'label' and 'value' properties.
*
* @return array
*/
public function get_conditional_logic_fields() {
return array();
}
/**
* Evaluate the rules defined for the Simple Condition field.
*
* @param string $setting_name_root The root name used as the prefix to the inputs that make up the Simple Condition field.
* @param array $form The form currently being processed.
* @param array $entry The entry currently being processed.
* @param array $feed The feed currently being processed or an empty array when the field is stored in the form settings.
*
* @return bool
*/
public function is_simple_condition_met( $setting_name_root, $form, $entry, $feed = array() ) {
$settings = empty( $feed ) ? $this->get_form_settings( $form ) : rgar( $feed, 'meta', array() );
$is_enabled = rgar( $settings, $setting_name_root . '_enabled' );
if ( ! $is_enabled ) {
// The setting is not enabled so we handle it as if the rules are met.
return true;
}
// Build the logic array to be used by Gravity Forms when evaluating the rules.
$logic = array(
'logicType' => 'all',
'rules' => array(
array(
'fieldId' => rgar( $settings, $setting_name_root . '_field_id' ),
'operator' => rgar( $settings, $setting_name_root . '_operator' ),
'value' => rgar( $settings, $setting_name_root . '_value' ),
),
)
);
return GFCommon::evaluate_conditional_logic( $logic, $form, $entry );
}
//-------------- Form settings ---------------------------------------------------
/**
* Initializes form settings page
* Hooks up the required scripts and actions for the Form Settings page
*/
public function form_settings_init() {
$view = rgget( 'view' );
$subview = rgget( 'subview' );
add_filter( 'gform_form_settings_menu', array( $this, 'add_form_settings_menu' ), 10, 2 );
if ( rgget( 'page' ) == 'gf_edit_forms' && $view == 'settings' && $subview == $this->_slug && $this->current_user_can_any( $this->_capabilities_form_settings ) ) {
require_once( GFCommon::get_base_path() . '/tooltips.php' );
add_action( 'gform_form_settings_page_' . $this->_slug, array( $this, 'form_settings_page' ) );
}
}
/**
* Initializes plugin settings page
* Hooks up the required scripts and actions for the Plugin Settings page
*/
public function plugin_page_init() {
if ( $this->current_user_can_any( $this->_capabilities_plugin_page ) ) {
//creates the subnav left menu
add_filter( 'gform_addon_navigation', array( $this, 'create_plugin_page_menu' ) );
}
}
/**
* Creates plugin page menu item
* Target of gform_addon_navigation filter. Creates a menu item in the left nav, linking to the plugin page
*
* @param $menus - Current list of menu items
*
* @return array - Returns a new list of menu items
*/
public function create_plugin_page_menu( $menus ) {
$menus[] = array( 'name' => $this->_slug, 'label' => $this->get_short_title(), 'callback' => array( $this, 'plugin_page_container' ), 'permission' => $this->_capabilities_plugin_page );
return $menus;
}
/**
* Renders the form settings page.
*
* Not intended to be overridden or called directly by Add-Ons.
* Sets up the form settings page.
*
* @ignore
*/
public function form_settings_page() {
GFFormSettings::page_header( $this->_title );
?>
get_current_form();
$form_id = $form['id'];
$form = gf_apply_filters( array( 'gform_admin_pre_render', $form_id ), $form );
if ( $this->method_is_overridden( 'form_settings' ) ) {
//enables plugins to override settings page by implementing a form_settings() function
$this->form_settings( $form );
} else {
//saves form settings if save button was pressed
$this->maybe_save_form_settings( $form );
//reads current form settings
$settings = $this->get_form_settings( $form );
$this->set_settings( $settings );
//reading addon fields
$sections = $this->form_settings_fields( $form );
GFCommon::display_admin_message();
$page_title = $this->form_settings_page_title();
if ( empty( $page_title ) ) {
$page_title = rgar( $sections[0], 'title' );
//using first section title as page title, so disable section title
$sections[0]['title'] = false;
}
$icon = $this->form_settings_icon();
if ( empty( $icon ) ) {
$icon = '';
}
?>
render_settings( $sections );
}
?>
is_save_postback() ) {
check_admin_referer( $this->_slug . '_save_settings', '_' . $this->_slug . '_save_settings_nonce' );
if ( ! $this->current_user_can_any( $this->_capabilities_form_settings ) ) {
GFCommon::add_error_message( esc_html__( "You don't have sufficient permissions to update the form settings.", 'gravityforms' ) );
return false;
}
// store a copy of the previous settings for cases where action would only happen if value has changed
$this->set_previous_settings( $this->get_form_settings( $form ) );
$settings = $this->get_posted_settings();
$sections = $this->form_settings_fields( $form );
$is_valid = $this->validate_settings( $sections, $settings );
$result = false;
if ( $is_valid ) {
$settings = $this->filter_settings( $sections, $settings );
$result = $this->save_form_settings( $form, $settings );
}
if ( $result ) {
GFCommon::add_message( $this->get_save_success_message( $sections ) );
} else {
GFCommon::add_error_message( $this->get_save_error_message( $sections ) );
}
return $result;
}
}
/***
* Saves form settings to form object
*
* @param array $form
* @param array $settings
*
* @return true|false True on success or false on error
*/
public function save_form_settings( $form, $settings ) {
$form[ $this->_slug ] = $settings;
$result = GFFormsModel::update_form_meta( $form['id'], $form );
return ! ( false === $result );
}
/**
* Checks whether the current Add-On has a form settings page.
*
* @return bool
*/
private function has_form_settings_page() {
return $this->method_is_overridden( 'form_settings_fields' ) || $this->method_is_overridden( 'form_settings' );
}
/**
* Custom form settings page
* Override this function to implement a complete custom form settings page.
* Before overriding this function, consider using the form_settings_fields() and specifying your field meta.
*/
public function form_settings( $form ) {
}
/**
* Custom form settings title
* Override this function to display a custom title on the Form Settings Page.
* By default, the first section in the configuration done in form_settings_fields() will be used as the page title.
* Use this function to override that behavior and add a custom page title.
*/
public function form_settings_page_title() {
return '';
}
/**
* Override this function to customize the form settings icon
*/
public function form_settings_icon() {
return '';
}
/**
* Checks whether the current Add-On has a plugin page.
*
* @return bool
*/
private function has_plugin_page() {
return $this->method_is_overridden( 'plugin_page' );
}
/**
* Override this function to create a custom plugin page
*/
public function plugin_page() {
}
/**
* Override this function to customize the plugin page icon
*/
public function plugin_page_icon() {
return '';
}
/**
* Override this function to customize the plugin page title
*/
public function plugin_page_title() {
return $this->_title;
}
/**
* Plugin page container
* Target of the plugin menu left nav icon. Displays the outer plugin page markup and calls plugin_page() to render the actual page.
* Override plugin_page() in order to provide a custom plugin page
*/
public function plugin_page_container() {
?>
plugin_page_icon();
if ( ! empty( $icon ) ) {
?>
plugin_page_title() ?>
plugin_page();
?>
has_app_settings() || $this->method_is_overridden( 'get_app_menu_items' );
}
/**
* Creates a top level app menu. Adds the app settings page automatically if it's configured.
* Target of the WordPress admin_menu action.
* Not intended to be overridden or called directly by add-ons.
*/
public function create_app_menu() {
$has_full_access = current_user_can( 'gform_full_access' );
$min_cap = GFCommon::current_user_can_which( $this->_capabilities_app_menu );
if ( empty( $min_cap ) ) {
$min_cap = 'gform_full_access';
}
$menu_items = $this->get_app_menu_items();
$addon_menus = array();
/**
* Filters through addon menus (filter by addon slugs)
*
* @param array $addon_menus A modifiable array of admin addon menus
*/
$addon_menus = apply_filters( 'gform_addon_app_navigation_' . $this->_slug, $addon_menus );
$parent_menu = self::get_parent_menu( $menu_items, $addon_menus );
if ( empty( $parent_menu ) ) {
return;
}
// Add a top-level left nav
$callback = isset( $parent_menu['callback'] ) ? $parent_menu['callback'] : array( $this, 'app_tab_page' );
global $menu;
$number = 10;
$menu_position = '16.' . $number;
while ( isset( $menu[$menu_position] ) ) {
$number += 10;
$menu_position = '16.' . $number;
}
/**
* Modify the menu position of an add-on menu
*
* @param int $menu_position The Menu position of the add-on menu
*/
$menu_position = apply_filters( 'gform_app_menu_position_' . $this->_slug, $menu_position );
$this->app_hook_suffix = add_menu_page( $this->get_short_title(), $this->get_short_title(), $has_full_access ? 'gform_full_access' : $min_cap, $parent_menu['name'], $callback, $this->get_app_menu_icon(), $menu_position );
if ( method_exists( $this, 'load_screen_options' ) ) {
add_action( "load-$this->app_hook_suffix", array( $this, 'load_screen_options' ) );
}
// Adding submenu pages
foreach ( $menu_items as $menu_item ) {
$callback = isset( $menu_item['callback'] ) ? $menu_item['callback'] : array( $this, 'app_tab_page' );
add_submenu_page( $parent_menu['name'], $menu_item['label'], $menu_item['label'], $has_full_access || empty( $menu_item['permission'] ) ? 'gform_full_access' : $menu_item['permission'], $menu_item['name'], $callback );
}
if ( is_array( $addon_menus ) ) {
foreach ( $addon_menus as $addon_menu ) {
add_submenu_page( $parent_menu['name'], $addon_menu['label'], $addon_menu['label'], $has_full_access ? 'gform_full_access' : $addon_menu['permission'], $addon_menu['name'], $addon_menu['callback'] );
}
}
if ( $this->has_app_settings() ) {
add_submenu_page( $parent_menu['name'], esc_html__( 'Settings', 'gravityforms' ), esc_html__( 'Settings', 'gravityforms' ), $has_full_access ? 'gform_full_access' : $this->_capabilities_app_settings, $this->_slug . '_settings', array( $this, 'app_tab_page' ) );
}
}
/**
* Returns the parent menu item
*
* @param $menu_items
* @param $addon_menus
*
* @return array|bool The parent menu araray or false if none
*/
private function get_parent_menu( $menu_items, $addon_menus ) {
$parent = false;
if ( GFCommon::current_user_can_any( $this->_capabilities_app_menu ) ) {
foreach ( $menu_items as $menu_item ) {
if ( $this->current_user_can_any( $menu_item['permission'] ) ) {
$parent = $menu_item;
break;
}
}
} elseif ( is_array( $addon_menus ) && sizeof( $addon_menus ) > 0 ) {
foreach ( $addon_menus as $addon_menu ) {
if ( $this->current_user_can_any( $addon_menu['permission'] ) ) {
$parent = array( 'name' => $addon_menu['name'], 'callback' => $addon_menu['callback'] );
break;
}
}
} elseif ( $this->has_app_settings() && $this->current_user_can_any( $this->_capabilities_app_settings ) ) {
$parent = array( 'name' => $this->_slug . '_settings', 'callback' => array( $this, 'app_settings' ) );
}
return $parent;
}
/**
* Override this function to create a top level app menu.
*
* e.g.
* $menu_item['name'] = 'gravitycontacts';
* $menu_item['label'] = __("Contacts", 'gravitycontacts');
* $menu_item['permission'] = 'gravitycontacts_view_contacts';
* $menu_item['callback'] = array($this, 'app_menu');
*
* @return array The array of menu items
*/
public function get_app_menu_items() {
return array();
}
/**
* Override this function to specify a custom icon for the top level app menu.
* Accepts a dashicon class or a URL.
*
* @return string
*/
public function get_app_menu_icon() {
return '';
}
/**
* Override this function to load custom screen options.
*
* e.g.
* $screen = get_current_screen();
* if(!is_object($screen) || $screen->id != $this->app_hook_suffix)
* return;
*
* if($this->is_contact_list_page()){
* $args = array(
* 'label' => __('Contacts per page', 'gravitycontacts'),
* 'default' => 20,
* 'option' => 'gcontacts_per_page'
* );
* add_screen_option( 'per_page', $args );
*/
public function load_screen_options() {
}
/**
* Handles the rendering of app menu items that implement the tabs UI.
*
* Not intended to be overridden or called directly by add-ons.
*/
public function app_tab_page() {
$page = sanitize_text_field( rgget( 'page' ) );
$current_tab = sanitize_text_field( rgget( 'view' ) );
if ( $page == $this->_slug . '_settings' ) {
$tabs = $this->get_app_settings_tabs();
} else {
$menu_items = $this->get_app_menu_items();
$current_menu_item = false;
foreach ( $menu_items as $menu_item ) {
if ( $menu_item['name'] == $page ) {
$current_menu_item = $menu_item;
break;
}
}
if ( empty( $current_menu_item ) ) {
return;
}
if ( empty( $current_menu_item['tabs'] ) ) {
return;
}
$tabs = $current_menu_item['tabs'];
}
if ( empty( $current_tab ) ) {
foreach ( $tabs as $tab ) {
if ( ! isset( $tab['permission'] ) || $this->current_user_can_any( $tab['permission'] ) ) {
$current_tab = $tab['name'];
break;
}
}
}
if ( empty( $current_tab ) ) {
wp_die( esc_html__( "You don't have adequate permission to view this page", 'gravityforms' ) );
}
foreach ( $tabs as $tab ) {
if ( $tab['name'] == $current_tab && isset( $tab['callback'] ) && is_callable( $tab['callback'] ) ) {
if ( isset( $tab['permission'] ) && ! $this->current_user_can_any( $tab['permission'] ) ) {
wp_die( esc_html__( "You don't have adequate permission to view this page", 'gravityforms' ) );
}
$title = rgar( $tab,'title' );
if ( empty( $title ) ) {
$title = isset( $tab['label'] ) ? $tab['label'] : $tab['name'];
}
$this->app_tab_page_header( $tabs, $current_tab, $title, '' );
call_user_func( $tab['callback'] );
$this->app_tab_page_footer();
return;
}
}
$this->app_tab_page_header( $tabs, $current_tab, $current_tab, '' );
/**
* Fires when an addon page and tab is accessed.
*
* Typically used to render settings tab content.
*/
$action_hook = 'gform_addon_app_' . $page . '_' . str_replace( ' ', '_', $current_tab );
do_action( $action_hook );
$this->app_tab_page_footer();
}
/**
* Returns the form settings for the Add-On
*
* @param $form
*
* @return array
*/
public function get_form_settings( $form ) {
return rgar( $form, $this->_slug );
}
/**
* Add the form settings tab.
*
* Override this function to add the tab conditionally.
*
*
* @param $tabs
* @param $form_id
*
* @return array
*/
public function add_form_settings_menu( $tabs, $form_id ) {
$tabs[] = array( 'name' => $this->_slug, 'label' => $this->get_short_title(), 'query' => array( 'fid' => null ), 'capabilities' => $this->_capabilities_form_settings );
return $tabs;
}
/**
* Override this function to specify the settings fields to be rendered on the form settings page
*/
public function form_settings_fields( $form ) {
// should return an array of sections, each section contains a title, description and an array of fields
return array();
}
//-------------- Plugin Settings ---------------------------------------------------
public function plugin_settings_init() {
$subview = rgget( 'subview' );
RGForms::add_settings_page(
array(
'name' => $this->_slug,
'tab_label' => $this->get_short_title(),
'title' => $this->plugin_settings_title(),
'handler' => array( $this, 'plugin_settings_page' ),
)
);
if ( rgget( 'page' ) == 'gf_settings' && $subview == $this->_slug && $this->current_user_can_any( $this->_capabilities_settings_page ) ) {
require_once( GFCommon::get_base_path() . '/tooltips.php' );
}
add_filter( 'plugin_action_links', array( $this, 'plugin_settings_link' ), 10, 2 );
}
public function plugin_settings_link( $links, $file ) {
if ( $file != $this->get_path() ) {
return $links;
}
array_unshift( $links, '' . esc_html__( 'Settings', 'gravityforms' ) . '' );
return $links;
}
/**
* Plugin settings page
*/
public function plugin_settings_page() {
$icon = $this->plugin_settings_icon();
if ( empty( $icon ) ) {
$icon = '';
}
?>
plugin_settings_title() ?>
has_deprecated_elements() ) : ?>
method_is_overridden( 'plugin_settings' ) ) {
//enables plugins to override settings page by implementing a plugin_settings() function
$this->plugin_settings();
} elseif ( $this->maybe_uninstall() ) {
?>
maybe_save_plugin_settings();
//reads main addon settings
$settings = $this->get_plugin_settings();
$this->set_settings( $settings );
//reading addon fields
$sections = $this->plugin_settings_fields();
GFCommon::display_admin_message();
//rendering settings based on fields and current settings
$this->render_settings( $sections, $settings );
//renders uninstall section
$this->render_uninstall();
}
}
public function plugin_settings_title() {
return sprintf( esc_html__( "%s Settings", "gravityforms" ), $this->get_short_title() );
}
public function plugin_settings_icon() {
return '';
}
/**
* Override this function to add a custom settings page.
*/
public function plugin_settings() {
}
/**
* Checks whether the current Add-On has a settings page.
*
* @return bool
*/
public function has_plugin_settings_page() {
return $this->method_is_overridden( 'plugin_settings_fields' ) || $this->method_is_overridden( 'plugin_settings_page' ) || $this->method_is_overridden( 'plugin_settings' );
}
/**
* Returns the currently saved plugin settings
* @return mixed
*/
public function get_plugin_settings() {
return get_option( 'gravityformsaddon_' . $this->_slug . '_settings' );
}
/**
* Get plugin setting
* Returns the plugin setting specified by the $setting_name parameter
*
* @param string $setting_name - Plugin setting to be returned
*
* @return mixed - Returns the specified plugin setting or null if the setting doesn't exist
*/
public function get_plugin_setting( $setting_name ) {
$settings = $this->get_plugin_settings();
return isset( $settings[ $setting_name ] ) ? $settings[ $setting_name ] : null;
}
/**
* Updates plugin settings with the provided settings
*
* @param array $settings - Plugin settings to be saved
*/
public function update_plugin_settings( $settings ) {
update_option( 'gravityformsaddon_' . $this->_slug . '_settings', $settings );
}
/**
* Saves the plugin settings if the submit button was pressed
*
*/
public function maybe_save_plugin_settings() {
if ( $this->is_save_postback() ) {
check_admin_referer( $this->_slug . '_save_settings', '_' . $this->_slug . '_save_settings_nonce' );
if ( ! $this->current_user_can_any( $this->_capabilities_settings_page ) ) {
GFCommon::add_error_message( esc_html__( "You don't have sufficient permissions to update the settings.", 'gravityforms' ) );
return false;
}
// store a copy of the previous settings for cases where action would only happen if value has changed
$this->set_previous_settings( $this->get_plugin_settings() );
$settings = $this->get_posted_settings();
$sections = $this->plugin_settings_fields();
$is_valid = $this->validate_settings( $sections, $settings );
if ( $is_valid ) {
$settings = $this->filter_settings( $sections, $settings );
$this->update_plugin_settings( $settings );
GFCommon::add_message( $this->get_save_success_message( $sections ) );
} else {
GFCommon::add_error_message( $this->get_save_error_message( $sections ) );
}
}
}
/**
* Override this function to specify the settings fields to be rendered on the plugin settings page
* @return array
*/
public function plugin_settings_fields() {
// should return an array of sections, each section contains a title, description and an array of fields
return array();
}
//-------------- App Settings ---------------------------------------------------
/**
* Returns the tabs for the settings app menu item
*
* Not intended to be overridden or called directly by add-ons.
*
* @return array|mixed|void
*/
public function get_app_settings_tabs() {
// Build left side options, always have app Settings first and Uninstall last, put add-ons in the middle
$setting_tabs = array( array( 'name' => 'settings', 'label' => esc_html__( 'Settings', 'gravityforms' ), 'callback' => array( $this, 'app_settings_tab' ) ) );
/**
* Filters the tabs within the settings menu.
*
* This filter is appended by the page slug. Ex: gform_addon_app_settings_menu_SLUG
*
* @param array $setting_tabs Contains the information on the settings tabs.
*/
$setting_tabs = apply_filters( 'gform_addon_app_settings_menu_' . $this->_slug, $setting_tabs );
if ( $this->current_user_can_uninstall() ) {
$setting_tabs[] = array( 'name' => 'uninstall', 'label' => esc_html__( 'Uninstall', 'gravityforms' ), 'callback' => array( $this, 'app_settings_uninstall_tab' ) );
}
ksort( $setting_tabs, SORT_NUMERIC );
return $setting_tabs;
}
/**
* Renders the app settings uninstall tab.
*
* Not intended to be overridden or called directly by add-ons.
*/
public function app_settings_uninstall_tab() {
if ( $this->maybe_uninstall() ) {
?>
maybe_save_app_settings();
//reads main addon settings
$settings = $this->get_app_settings();
$this->set_settings( $settings );
//reading addon fields
$sections = $this->app_settings_fields();
GFCommon::display_admin_message();
//rendering settings based on fields and current settings
$this->render_settings( $sections, $settings );
}
}
/**
* Override this function to specific a custom app settings title
*
* @return string
*/
public function app_settings_title() {
return sprintf( esc_html__( '%s Settings', 'gravityforms' ), $this->get_short_title() );
}
/**
* Override this function to specific a custom app settings icon
*
* @return string
*/
public function app_settings_icon() {
return '';
}
/**
* Checks whether the current Add-On has a settings page.
*
* @return bool
*/
public function has_app_settings() {
return $this->method_is_overridden( 'app_settings_fields' ) || $this->method_is_overridden( 'app_settings' );
}
/**
* Override this function to add a custom app settings page.
*/
public function app_settings() {
}
/**
* Returns the currently saved plugin settings
* @return mixed
*/
public function get_app_settings() {
return get_option( 'gravityformsaddon_' . $this->_slug . '_app_settings' );
}
/**
* Get app setting
* Returns the app setting specified by the $setting_name parameter
*
* @param string $setting_name - Plugin setting to be returned
*
* @return mixed - Returns the specified plugin setting or null if the setting doesn't exist
*/
public function get_app_setting( $setting_name ) {
$settings = $this->get_app_settings();
return isset( $settings[ $setting_name ] ) ? $settings[ $setting_name ] : null;
}
/**
* Updates app settings with the provided settings
*
* @param array $settings - App settings to be saved
*/
public function update_app_settings( $settings ) {
update_option( 'gravityformsaddon_' . $this->_slug . '_app_settings', $settings );
}
/**
* Saves the plugin settings if the submit button was pressed
*
*/
public function maybe_save_app_settings() {
if ( $this->is_save_postback() ) {
check_admin_referer( $this->_slug . '_save_settings', '_' . $this->_slug . '_save_settings_nonce' );
if ( ! $this->current_user_can_any( $this->_capabilities_app_settings ) ) {
GFCommon::add_error_message( esc_html__( "You don't have sufficient permissions to update the settings.", 'gravityforms' ) );
return false;
}
// store a copy of the previous settings for cases where action would only happen if value has changed
$this->set_previous_settings( $this->get_app_settings() );
$settings = $this->get_posted_settings();
$sections = $this->app_settings_fields();
$is_valid = $this->validate_settings( $sections, $settings );
if ( $is_valid ) {
$settings = $this->filter_settings( $sections, $settings );
$this->update_app_settings( $settings );
GFCommon::add_message( $this->get_save_success_message( $sections ) );
} else {
GFCommon::add_error_message( $this->get_save_error_message( $sections ) );
}
}
}
/**
* Override this function to specify the settings fields to be rendered on the plugin settings page
* @return array
*/
public function app_settings_fields() {
// should return an array of sections, each section contains a title, description and an array of fields
return array();
}
/**
* Returns an flattened array of field settings for the specified settings type ignoring sections.
*
* @param string $settings_type The settings type. e.g. 'plugin'
*
* @return array
*/
public function settings_fields_only( $settings_type = 'plugin' ) {
$fields = array();
if ( ! is_callable( array( $this, "{$settings_type}_settings_fields" ) ) ) {
return $fields;
}
$sections = call_user_func( array( $this, "{$settings_type}_settings_fields" ) );
foreach ( $sections as $section ) {
foreach ( $section['fields'] as $field ) {
$fields[] = $field;
}
}
return $fields;
}
//-------------- Uninstall ---------------
/**
* Override this function to customize the markup for the uninstall section on the plugin settings page
*/
public function render_uninstall() {
?>
', esc_html( $this->get_short_title() ), '' );
}
public function uninstall_confirm_message() {
return sprintf( __( "Warning! ALL %s settings will be deleted. This cannot be undone. 'OK' to delete, 'Cancel' to stop", 'gravityforms' ), __( $this->get_short_title() ) );
}
/**
* Not intended to be overridden or called directly by Add-Ons.
*
* @ignore
*/
public function maybe_uninstall() {
if ( rgpost( 'uninstall' ) ) {
check_admin_referer( 'uninstall', 'gf_addon_uninstall' );
return $this->uninstall_addon();
}
return false;
}
/**
* Removes all settings and deactivates the Add-On.
*
* Not intended to be overridden or called directly by Add-Ons.
*
* @ignore
*/
public function uninstall_addon() {
if ( ! $this->current_user_can_uninstall() ) {
die( esc_html__( "You don't have adequate permission to uninstall this add-on: " . $this->_title, 'gravityforms' ) );
}
$continue = $this->uninstall();
if ( false === $continue ) {
return false;
}
global $wpdb;
$forms = GFFormsModel::get_forms();
$all_form_ids = array();
// remove entry meta
$meta_table = version_compare( GFFormsModel::get_database_version(), '2.3-dev-1', '<' ) ? GFFormsModel::get_lead_meta_table_name() : GFFormsModel::get_entry_meta_table_name();
remove_filter( 'query', array( 'GFForms', 'filter_query' ) );
foreach ( $forms as $form ) {
$all_form_ids[] = $form->id;
$entry_meta = $this->get_entry_meta( array(), $form->id );
if ( is_array( $entry_meta ) ) {
foreach ( array_keys( $entry_meta ) as $meta_key ) {
$sql = $wpdb->prepare( "DELETE from $meta_table WHERE meta_key=%s", $meta_key );
$wpdb->query( $sql );
}
}
}
add_filter( 'query', array( 'GFForms', 'filter_query' ) );
//remove form settings
if ( ! empty( $all_form_ids ) ) {
$form_metas = GFFormsModel::get_form_meta_by_id( $all_form_ids );
require_once( GFCommon::get_base_path() . '/form_detail.php' );
foreach ( $form_metas as $form_meta ) {
if ( isset( $form_meta[ $this->_slug ] ) ) {
unset( $form_meta[ $this->_slug ] );
$form_json = json_encode( $form_meta );
GFFormDetail::save_form_info( $form_meta['id'], addslashes( $form_json ) );
}
}
}
//removing options
delete_option( 'gravityformsaddon_' . $this->_slug . '_settings' );
delete_option( 'gravityformsaddon_' . $this->_slug . '_app_settings' );
delete_option( 'gravityformsaddon_' . $this->_slug . '_version' );
//Deactivating plugin
deactivate_plugins( $this->get_path() );
update_option( 'recently_activated', array( $this->get_path() => time() ) + (array) get_option( 'recently_activated' ) );
return true;
}
/**
* Called when the user chooses to uninstall the Add-On - after permissions have been checked and before removing
* all Add-On settings and Form settings.
*
* Override this method to perform additional functions such as dropping database tables.
*
*
* Return false to cancel the uninstall request.
*/
public function uninstall() {
return true;
}
//-------------- Enforce minimum GF version ---------------------------------------------------
/**
* Target for the after_plugin_row action hook. Checks whether the current version of Gravity Forms
* is supported and outputs a message just below the plugin info on the plugins page.
*
* Not intended to be overridden or called directly by Add-Ons.
*
* @since Unknown
* @since 2.4.15 Update to improve multisite updates.
*
* @param string $plugin_name The plugin filename. Immediately overwritten.
* @param array $plugin_data An array of plugin data.
*/
public function plugin_row( $plugin_name, $plugin_data ) {
if ( false === $this->_enable_rg_autoupgrade && ! self::is_gravityforms_supported( $this->_min_gravityforms_version ) ) {
$message = $this->plugin_message();
self::display_plugin_message( $message, true );
}
GFForms::maybe_display_update_notification( $plugin_name, $plugin_data, $this->get_slug(), $this->_version );
}
/**
* Returns the message that will be displayed if the current version of Gravity Forms is not supported.
*
* Override this method to display a custom message.
*/
public function plugin_message() {
$message = sprintf( esc_html__( 'Gravity Forms %s is required. Activate it now or %spurchase it today!%s', 'gravityforms' ), $this->_min_gravityforms_version, "", '' );
return $message;
}
/**
* Formats and outs a message for the plugin row.
*
* Not intended to be overridden or called directly by Add-Ons.
*
* @ignore
*
* @param $message
* @param bool $is_error
*/
public static function display_plugin_message( $message, $is_error = false ) {
$style = $is_error ? 'style="background-color: #ffebe8;"' : '';
echo '
' . $message . '
';
}
//--------------- Logging -------------------------------------------------------------
/**
* Writes an error message to the Gravity Forms log. Requires the Gravity Forms logging Add-On.
*
* Not intended to be overridden by Add-Ons.
*
* @ignore
*/
public function log_error( $message ) {
if ( class_exists( 'GFLogging' ) ) {
GFLogging::include_logger();
GFLogging::log_message( $this->_slug, $message, KLogger::ERROR );
}
}
/**
* Writes an error message to the Gravity Forms log. Requires the Gravity Forms logging Add-On.
*
* Not intended to be overridden by Add-Ons.
*
* @ignore
*/
public function log_debug( $message ) {
if ( class_exists( 'GFLogging' ) ) {
GFLogging::include_logger();
GFLogging::log_message( $this->_slug, $message, KLogger::DEBUG );
}
}
//--------------- Locking ------------------------------------------------------------
/**
* Returns the configuration for locking
*
* 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
* );
*
* Override this method to implement locking
*/
public function get_locking_config() {
return array();
}
/**
* Returns TRUE if the current page is the edit page. Otherwise, returns FALSE
*
* Override this method to implement locking on the edit page.
*/
public function is_locking_edit_page() {
return false;
}
/**
* Returns TRUE if the current page is the list page. Otherwise, returns FALSE
*
* Override this method to display locking info on the list page.
*/
public function is_locking_list_page() {
return false;
}
/**
* Returns TRUE if the current page is the view page. Otherwise, returns FALSE
*
* Override this method to display locking info on the view page.
*/
public function is_locking_view_page() {
return false;
}
/**
* Returns the ID of the object to be locked. E.g. Form ID
*
* Override this method to implement locking
*/
public function get_locking_object_id() {
return 0;
}
/**
* Outputs information about the user currently editing the specified object
*
* @param int $object_id The Object ID
* @param bool $echo Whether to echo
*
* @return string The markup for the lock info
*/
public function lock_info( $object_id, $echo = true ) {
$gf_locking = new GFAddonLocking( $this->get_locking_config(), $this );
$lock_info = $gf_locking->lock_info( $object_id, false );
if ( $echo ) {
echo $lock_info;
}
return $lock_info;
}
/**
* Outputs class for the row for the specified Object ID on the list page.
*
* @param int $object_id The object ID
* @param bool $echo Whether to echo
*
* @return string The markup for the class
*/
public function list_row_class( $object_id, $echo = true ) {
$gf_locking = new GFAddonLocking( $this->get_locking_config(), $this );
$class = $gf_locking->list_row_class( $object_id, false );
if ( $echo ) {
echo $class;
}
return $class;
}
/**
* Checked whether an object is locked
*
* @param int|mixed $object_id The object ID
*
* @return bool
*/
public function is_object_locked( $object_id ) {
$gf_locking = new GFAddonLocking( $this->get_locking_config(), $this );
return $gf_locking->is_locked( $object_id );
}
//------------- Field Value Retrieval -------------------------------------------------
/**
* Returns the value of the mapped field.
*
* @param string $setting_name
* @param array $form
* @param array $entry
* @param mixed $settings
*
* @return string
*/
public function get_mapped_field_value( $setting_name, $form, $entry, $settings = false ) {
$field_id = $this->get_setting( $setting_name, '', $settings );
return $this->get_field_value( $form, $entry, $field_id );
}
/**
* Returns the value of the selected field.
*
* @access private
*
* @param array $form
* @param array $entry
* @param string $field_id
*
* @return string field value
*/
public function get_field_value( $form, $entry, $field_id ) {
$field_value = '';
switch ( strtolower( $field_id ) ) {
case 'form_title':
$field_value = rgar( $form, 'title' );
break;
case 'date_created':
$date_created = rgar( $entry, strtolower( $field_id ) );
if ( empty( $date_created ) ) {
//the date created may not yet be populated if this function is called during the validation phase and the entry is not yet created
$field_value = gmdate( 'Y-m-d H:i:s' );
} else {
$field_value = $date_created;
}
break;
case 'ip':
case 'source_url':
case 'id':
$field_value = rgar( $entry, strtolower( $field_id ) );
break;
default:
$field = GFFormsModel::get_field( $form, $field_id );
if ( is_object( $field ) ) {
$is_integer = $field_id == intval( $field_id );
$input_type = $field->get_input_type();
if ( $is_integer && $input_type == 'address' ) {
$field_value = $this->get_full_address( $entry, $field_id );
} elseif ( $is_integer && $input_type == 'name' ) {
$field_value = $this->get_full_name( $entry, $field_id );
} elseif ( is_callable( array( $this, "get_{$input_type}_field_value" ) ) ) {
$field_value = call_user_func( array( $this, "get_{$input_type}_field_value" ), $entry, $field_id, $field );
} else {
$field_value = $field->get_value_export( $entry, $field_id );
}
} else {
$field_value = rgar( $entry, $field_id );
}
}
/**
* A generic filter allowing the field value to be overridden. Form and field id modifiers supported.
*
* @param string $field_value The value to be overridden.
* @param array $form The Form currently being processed.
* @param array $entry The Entry currently being processed.
* @param string $field_id The ID of the Field currently being processed.
* @param string $slug The add-on slug e.g. gravityformsactivecampaign.
*
* @since 1.9.15.12
*
* @return string
*/
$field_value = gf_apply_filters( array( 'gform_addon_field_value', $form['id'], $field_id ), $field_value, $form, $entry, $field_id, $this->_slug );
return $this->maybe_override_field_value( $field_value, $form, $entry, $field_id );
}
/**
* Enables use of the gform_SLUG_field_value filter to override the field value. Override this function to prevent the filter being used or to implement a custom filter.
*
* @param string $field_value
* @param array $form
* @param array $entry
* @param string $field_id
*
* @return string
*/
public function maybe_override_field_value( $field_value, $form, $entry, $field_id ) {
/* Get Add-On slug */
$slug = str_replace( 'gravityforms', '', $this->_slug );
return gf_apply_filters( array(
"gform_{$slug}_field_value",
$form['id'],
$field_id
), $field_value, $form, $entry, $field_id );
}
/**
* Returns the combined value of the specified Address field.
*
* @param array $entry
* @param string $field_id
*
* @return string
*/
public function get_full_address( $entry, $field_id ) {
return GF_Fields::get( 'address' )->get_value_export( $entry, $field_id );
}
/**
* Returns the combined value of the specified Name field.
*
* @param array $entry
* @param string $field_id
*
* @return string
*/
public function get_full_name( $entry, $field_id ) {
return GF_Fields::get( 'name' )->get_value_export( $entry, $field_id );
}
/**
* Returns the value of the specified List field.
*
* @param array $entry
* @param string $field_id
* @param GF_Field_List $field
*
* @return string
*/
public function get_list_field_value( $entry, $field_id, $field ) {
return $field->get_value_export( $entry, $field_id );
}
/**
* Returns the field ID of the first field of the desired type.
*
* @access public
* @param string $field_type
* @param int $subfield_id (default: null)
* @param int $form_id (default: null)
* @return string
*/
public function get_first_field_by_type( $field_type, $subfield_id = null, $form_id = null, $return_first_only = true ) {
/* Get the current form ID. */
if ( rgblank( $form_id ) ) {
$form_id = rgget( 'id' );
}
/* Get the form. */
$form = GFAPI::get_form( $form_id );
/* Get the request field type for the form. */
$fields = GFAPI::get_fields_by_type( $form, array( $field_type ) );
if ( count( $fields ) == 0 || ( count( $fields ) > 1 && $return_first_only ) ) {
return null;
} else {
if ( rgblank( $subfield_id ) ) {
return $fields[0]->id;
} else {
return $fields[0]->id . '.' . $subfield_id;
}
}
}
//--------------- Notes ------------------
/**
* Override this function to specify a custom avatar (i.e. the payment gateway logo) for entry notes created by the Add-On
* @return string - A fully qualified URL for the avatar
*/
public function note_avatar() {
return false;
}
public function notes_avatar( $avatar, $note ) {
if ( $note->user_name == $this->_short_title && empty( $note->user_id ) && $this->method_is_overridden( 'note_avatar', 'GFAddOn' ) ) {
$new_avatar = $this->note_avatar();
}
return empty( $new_avatar ) ? $avatar : "";
}
public function add_note( $entry_id, $note, $note_type = null ) {
$user_id = 0;
$user_name = $this->_short_title;
GFFormsModel::add_note( $entry_id, $user_id, $user_name, $note, $note_type );
}
//-------------- Helper functions ---------------------------------------------------
protected final function method_is_overridden( $method_name, $base_class = 'GFAddOn' ) {
$reflector = new ReflectionMethod( $this, $method_name );
$name = $reflector->getDeclaringClass()->getName();
return $name !== $base_class;
}
/**
* Returns the url of the root folder of the current Add-On.
*
* @param string $full_path Optional. The full path the the plugin file.
*
* @return string
*/
public function get_base_url( $full_path = '' ) {
if ( empty( $full_path ) ) {
$full_path = $this->_full_path;
}
return plugins_url( null, $full_path );
}
/**
* Returns the url of the Add-On Framework root folder.
*
* @return string
*/
final public static function get_gfaddon_base_url() {
return plugins_url( null, __FILE__ );
}
/**
* Returns the physical path of the Add-On Framework root folder.
*
* @return string
*/
final public static function get_gfaddon_base_path() {
return self::_get_base_path();
}
/**
* Returns the physical path of the plugins root folder.
*
* @param string $full_path
*
* @return string
*/
public function get_base_path( $full_path = '' ) {
if ( empty( $full_path ) ) {
$full_path = $this->_full_path;
}
$folder = basename( dirname( $full_path ) );
return WP_PLUGIN_DIR . '/' . $folder;
}
/**
* Returns the physical path of the Add-On Framework root folder
*
* @return string
*/
private static function _get_base_path() {
$folder = basename( dirname( __FILE__ ) );
return GFCommon::get_base_path() . '/includes/' . $folder;
}
/**
* Returns the URL of the Add-On Framework root folder
*
* @return string
*/
private static function _get_base_url() {
$folder = basename( dirname( __FILE__ ) );
return GFCommon::get_base_url() . '/includes/' . $folder;
}
/**
* Checks whether the Gravity Forms is installed.
*
* @return bool
*/
public function is_gravityforms_installed() {
return class_exists( 'GFForms' );
}
public function table_exists( $table_name ) {
return GFCommon::table_exists( $table_name );
}
/**
* Checks whether the current version of Gravity Forms is supported
*
* @param $min_gravityforms_version
*
* @return bool|mixed
*/
public function is_gravityforms_supported( $min_gravityforms_version = '' ) {
if ( isset( $this->_min_gravityforms_version ) && empty( $min_gravityforms_version ) ) {
$min_gravityforms_version = $this->_min_gravityforms_version;
}
if ( empty( $min_gravityforms_version ) ) {
return true;
}
if ( class_exists( 'GFCommon' ) ) {
$is_correct_version = version_compare( GFCommon::$version, $min_gravityforms_version, '>=' );
return $is_correct_version;
} else {
return false;
}
}
/**
* Returns this plugin's short title. Used to display the plugin title in small areas such as tabs
*/
public function get_short_title() {
return isset( $this->_short_title ) ? $this->_short_title : $this->_title;
}
/**
* Return this plugin's version.
*
* @since 2.0
* @access public
*
* @return string
*/
public function get_version() {
return $this->_version;
}
/**
* Returns the unescaped URL for the plugin settings tab associated with this plugin
*
*/
public function get_plugin_settings_url() {
return add_query_arg( array( 'page' => 'gf_settings', 'subview' => $this->_slug ), admin_url( 'admin.php' ) );
}
/**
* Returns the current form object based on the id query var. Otherwise returns false
*/
public function get_current_form() {
return rgempty( 'id', $_GET ) ? false : GFFormsModel::get_form_meta( rgget( 'id' ) );
}
/**
* Returns TRUE if the current request is a postback, otherwise returns FALSE
*/
public function is_postback() {
return is_array( $_POST ) && count( $_POST ) > 0;
}
/**
* Returns TRUE if the settings "Save" button was pressed
*/
public function is_save_postback() {
return ! rgempty( 'gform-settings-save' );
}
/**
* Returns TRUE if the current page is the form editor page. Otherwise, returns FALSE
*/
public function is_form_editor() {
if ( rgget( 'page' ) == 'gf_edit_forms' && ! rgempty( 'id', $_GET ) && rgempty( 'view', $_GET ) ) {
return true;
}
return false;
}
/**
* Returns TRUE if the current page is the form list page. Otherwise, returns FALSE
*/
public function is_form_list() {
if ( rgget( 'page' ) == 'gf_edit_forms' && rgempty( 'id', $_GET ) && rgempty( 'view', $_GET ) ) {
return true;
}
return false;
}
/**
* Returns TRUE if the current page is the form settings page, or a specific form settings tab (specified by the $tab parameter). Otherwise returns FALSE
*
* @param string $tab - Specifies a specific form setting page/tab
*
* @return bool
*/
public function is_form_settings( $tab = null ) {
$is_form_settings = rgget( 'page' ) == 'gf_edit_forms' && rgget( 'view' ) == 'settings';
$is_tab = $this->_tab_matches( $tab );
if ( $is_form_settings && $is_tab ) {
return true;
} else {
return false;
}
}
private function _tab_matches( $tabs ) {
if ( $tabs == null ) {
return true;
}
if ( ! is_array( $tabs ) ) {
$tabs = array( $tabs );
}
$current_tab = rgempty( 'subview', $_GET ) ? 'settings' : rgget( 'subview' );
foreach ( $tabs as $tab ) {
if ( strtolower( $tab ) == strtolower( $current_tab ) ) {
return true;
}
}
}
/**
* Returns TRUE if the current page is the plugin settings main page, or a specific plugin settings tab (specified by the $tab parameter). Otherwise returns FALSE
*
* @param string $tab - Specifies a specific plugin setting page/tab.
*
* @return bool
*/
public function is_plugin_settings( $tab = '' ) {
$is_plugin_settings = rgget( 'page' ) == 'gf_settings';
$is_tab = $this->_tab_matches( $tab );
if ( $is_plugin_settings && $is_tab ) {
return true;
} else {
return false;
}
}
/**
* Returns TRUE if the current page is the app settings main page, or a specific apps settings tab (specified by the $tab parameter). Otherwise returns FALSE
*
* @param string $tab - Specifies a specific app setting page/tab.
*
* @return bool
*/
public function is_app_settings( $tab = '' ) {
$is_app_settings = rgget( 'page' ) == $this->_slug . '_settings';
$is_tab = $this->_tab_matches( $tab );
if ( $is_app_settings && $is_tab ) {
return true;
} else {
return false;
}
}
/**
* Returns TRUE if the current page is the plugin page. Otherwise returns FALSE
* @return bool
*/
public function is_plugin_page() {
return strtolower( rgget( 'page' ) ) == strtolower( $this->_slug );
}
/**
* Returns TRUE if the current page is the entry view page. Otherwise, returns FALSE
* @return bool
*/
public function is_entry_view() {
if ( rgget( 'page' ) == 'gf_entries' && rgget( 'view' ) == 'entry' && ( ! isset( $_POST['screen_mode'] ) || rgpost( 'screen_mode' ) == 'view' ) ) {
return true;
}
return false;
}
/**
* Returns TRUE if the current page is the entry edit page. Otherwise, returns FALSE
* @return bool
*/
public function is_entry_edit() {
if ( rgget( 'page' ) == 'gf_entries' && rgget( 'view' ) == 'entry' && rgpost( 'screen_mode' ) == 'edit' ) {
return true;
}
return false;
}
public function is_entry_list() {
if ( rgget( 'page' ) == 'gf_entries' && ( rgget( 'view' ) == 'entries' || rgempty( 'view', $_GET ) ) ) {
return true;
}
return false;
}
/**
* Returns TRUE if the current page is the results page. Otherwise, returns FALSE
*/
public function is_results() {
if ( rgget( 'page' ) == 'gf_entries' && rgget( 'view' ) == 'gf_results_' . $this->_slug ) {
return true;
}
return false;
}
/**
* Returns TRUE if the current page is the print page. Otherwise, returns FALSE
*/
public function is_print() {
if ( rgget( 'gf_page' ) == 'print-entry' ) {
return true;
}
return false;
}
/**
* Returns TRUE if the current page is the preview page. Otherwise, returns FALSE
*/
public function is_preview() {
if ( rgget( 'gf_page' ) == 'preview' ) {
return true;
}
return false;
}
public function has_deprecated_elements() {
$deprecated = GFAddOn::get_all_deprecated_protected_methods( get_class( $this ) );
if ( ! empty( $deprecated ) ) {
return true;
}
return false;
}
public static function get_all_deprecated_protected_methods($add_on_class_name = ''){
$deprecated = array();
$deprecated = array_merge( $deprecated, self::get_deprecated_protected_methods_for_base_class( 'GFAddOn', $add_on_class_name )) ;
$deprecated = array_merge( $deprecated, self::get_deprecated_protected_methods_for_base_class( 'GFFeedAddOn', $add_on_class_name ) ) ;
$deprecated = array_merge( $deprecated, self::get_deprecated_protected_methods_for_base_class( 'GFPaymentAddOn', $add_on_class_name ) ) ;
return $deprecated;
}
public static function get_deprecated_protected_methods_for_base_class( $base_class_name, $add_on_class_name = '' ) {
$deprecated = array();
if ( ! class_exists( $base_class_name ) ) {
return $deprecated;
}
$base_class_names = array(
'GFAddOn',
'GFFeedAddOn',
'GFPaymentAddOn'
);
$base_class = new ReflectionClass( $base_class_name );
$classes = empty($add_on_class_name) ? get_declared_classes() : array( $add_on_class_name );
foreach ( $classes as $class ) {
if ( ! is_subclass_of( $class, $base_class_name ) || in_array( $class, $base_class_names ) ) {
continue;
}
$add_on_class = new ReflectionClass( $class );
$add_on_methods = $add_on_class->getMethods( ReflectionMethod::IS_PROTECTED );
foreach ( $add_on_methods as $method ) {
$method_name = $method->getName();
$base_has_method = $base_class->hasMethod( $method_name );
$is_declared_by_base_class = $base_has_method && $base_class->getMethod( $method_name )->getDeclaringClass()->getName() == $base_class_name;
$is_overridden = $method->getDeclaringClass()->getName() == $class;
if ( $is_declared_by_base_class && $is_overridden ) {
$deprecated[] = $class . '::' . $method_name;
}
}
}
return $deprecated;
}
public function maybe_wp_kses( $html, $allowed_html = 'post', $allowed_protocols = array() ) {
return GFCommon::maybe_wp_kses( $html, $allowed_html, $allowed_protocols );
}
/**
* Returns the slug for the add-on.
*
* @since 2.0
*/
public function get_slug() {
return $this->_slug;
}
/**
* Returns the path for the add-on.
*
* @since 2.2
*/
public function get_path() {
return $this->_path;
}
/**
* Fixes the add-on _path property value, if the directory has been renamed.
*
* @since 2.4.17
*/
public function update_path() {
$path_dirname = dirname( $this->_path );
if ( $path_dirname !== '.' ) {
$full_path_dirname = basename( dirname( $this->_full_path ) );
if ( $path_dirname !== $full_path_dirname ) {
$this->_path = trailingslashit( $full_path_dirname ) . basename( $this->_path );
}
}
}
/**
* Get all or a specific capability for Add-On.
*
* @since 2.2.5.27
* @access public
*
* @param string $capability Capability to return.
*
* @return string|array
*/
public function get_capabilities( $capability = '' ) {
if ( rgblank( $capability ) ) {
return $this->_capabilities;
}
return isset( $this->{'_capabilities_' . $capability} ) ? $this->{'_capabilities_' . $capability} : array();
}
/**
* Initializing translations.
*
* @since 2.0.7
*/
public function load_text_domain() {
GFCommon::load_gf_text_domain( $this->_slug, plugin_basename( dirname( $this->_full_path ) ) );
}
/***
* Determines if the current user has the proper cabalities to uninstall this add-on
* Add-ons that have been network activated can only be uninstalled by a network admin.
*
* @since 2.3.1.12
* @access public
*
* @return bool True if current user can uninstall this add-on. False otherwise
*/
public function current_user_can_uninstall(){
return GFCommon::current_user_can_uninstall( $this->_capabilities_uninstall, $this->get_path() );
}
}