GFAddOn

Handles all tasks mostly common to any Gravity Forms Add-On, including third party ones.

Defined (1)

The class is defined in the following location(s).

/includes/addon/class-gf-addon.php  
  1. abstract class GFAddOn { 
  2.  
  3. /** 
  4. * @var string Version number of the Add-On 
  5. */ 
  6. protected $_version; 
  7. /** 
  8. * @var string Gravity Forms minimum version requirement 
  9. */ 
  10. protected $_min_gravityforms_version; 
  11. /** 
  12. * @var string URL-friendly identifier used for form settings, add-on settings, text domain localization... 
  13. */ 
  14. protected $_slug; 
  15. /** 
  16. * @var string Relative path to the plugin from the plugins folder. Example "gravityforms/gravityforms.php" 
  17. */ 
  18. protected $_path; 
  19. /** 
  20. * @var string Full path the the plugin. Example: __FILE__ 
  21. */ 
  22. protected $_full_path; 
  23. /** 
  24. * @var string URL to the Gravity Forms website. Example: 'http://www.gravityforms.com' OR affiliate link. 
  25. */ 
  26. protected $_url; 
  27. /** 
  28. * @var string Title of the plugin to be used on the settings page, form settings and plugins page. Example: 'Gravity Forms MailChimp Add-On' 
  29. */ 
  30. protected $_title; 
  31. /** 
  32. * @var string Short version of the plugin title to be used on menus and other places where a less verbose string is useful. Example: 'MailChimp' 
  33. */ 
  34. protected $_short_title; 
  35. /** 
  36. * @var array Members plugin integration. List of capabilities to add to roles. 
  37. */ 
  38. protected $_capabilities = array(); 
  39. /** 
  40. * @var string The hook suffix for the app menu 
  41. */ 
  42. public $app_hook_suffix; 
  43.  
  44. private $_saved_settings = array(); 
  45. private $_previous_settings = array(); 
  46.  
  47. /** 
  48. * @var array Stores a copy of setting fields that failed validation; only populated after validate_settings() has been called. 
  49. */ 
  50. private $_setting_field_errors = array(); 
  51.  
  52. // ------------ Permissions ----------- 
  53. /** 
  54. * @var string|array A string or an array of capabilities or roles that have access to the settings page 
  55. */ 
  56. protected $_capabilities_settings_page = array(); 
  57. /** 
  58. * @var string|array A string or an array of capabilities or roles that have access to the form settings 
  59. */ 
  60. protected $_capabilities_form_settings = array(); 
  61. /** 
  62. * @var string|array A string or an array of capabilities or roles that have access to the plugin page 
  63. */ 
  64. protected $_capabilities_plugin_page = array(); 
  65. /** 
  66. * @var string|array A string or an array of capabilities or roles that have access to the app menu 
  67. */ 
  68. protected $_capabilities_app_menu = array(); 
  69. /** 
  70. * @var string|array A string or an array of capabilities or roles that have access to the app settings page 
  71. */ 
  72. protected $_capabilities_app_settings = array(); 
  73. /** 
  74. * @var string|array A string or an array of capabilities or roles that can uninstall the plugin 
  75. */ 
  76. protected $_capabilities_uninstall = array(); 
  77.  
  78. // ------------ RG Autoupgrade ----------- 
  79.  
  80. /** 
  81. * @var bool Used by Rocketgenius plugins to activate auto-upgrade. 
  82. * @ignore 
  83. */ 
  84. protected $_enable_rg_autoupgrade = false; 
  85.  
  86. // ------------ Private ----------- 
  87.  
  88. private $_no_conflict_scripts = array(); 
  89. private $_no_conflict_styles = array(); 
  90. private $_preview_styles = array(); 
  91. private $_print_styles = array(); 
  92. private static $_registered_addons = array( 'active' => array(), 'inactive' => array() ); 
  93.  
  94. /** 
  95. * Class constructor which hooks the instance into the WordPress init action 
  96. */ 
  97. function __construct() { 
  98.  
  99. add_action( 'init', array( $this, 'init' ) ); 
  100.  
  101. if ( $this->_enable_rg_autoupgrade ) { 
  102. require_once( 'class-gf-auto-upgrade.php' ); 
  103. $is_gravityforms_supported = $this->is_gravityforms_supported( $this->_min_gravityforms_version ); 
  104. new GFAutoUpgrade( $this->_slug, $this->_version, $this->_min_gravityforms_version, $this->_title, $this->_full_path, $this->_path, $this->_url, $is_gravityforms_supported ); 
  105.  
  106. $this->pre_init(); 
  107.  
  108. /** 
  109. * Registers an addon so that it gets initialized appropriately 
  110. * @param string $class - The class name 
  111. * @param string $overrides - Specify the class to replace/override 
  112. */ 
  113. public static function register( $class, $overrides = null ) { 
  114.  
  115. //Ignore classes that have been marked as inactive 
  116. if ( in_array( $class, self::$_registered_addons['inactive'] ) ) { 
  117. return; 
  118.  
  119. //Mark classes as active. Override existing active classes if they are supposed to be overridden 
  120. $index = array_search( $overrides, self::$_registered_addons['active'] ); 
  121. if ( $index !== false ) { 
  122. self::$_registered_addons['active'][ $index ] = $class; 
  123. } else { 
  124. self::$_registered_addons['active'][] = $class; 
  125.  
  126. //Mark overridden classes as inactive. 
  127. if ( ! empty( $overrides ) ) { 
  128. self::$_registered_addons['inactive'][] = $overrides; 
  129.  
  130.  
  131. /** 
  132. * Gets all active, registered Add-Ons. 
  133. *  
  134. * @static 
  135. * @return array - Active, registered Add-Ons 
  136. */ 
  137. public static function get_registered_addons() { 
  138. return self::$_registered_addons['active']; 
  139.  
  140. /** 
  141. * Initializes all addons. 
  142. */ 
  143. public static function init_addons() { 
  144.  
  145. //Removing duplicate add-ons 
  146. $active_addons = array_unique( self::$_registered_addons['active'] ); 
  147.  
  148. foreach ( $active_addons as $addon ) { 
  149.  
  150. call_user_func( array( $addon, 'get_instance' ) ); 
  151.  
  152.  
  153. /** 
  154. * Gets executed before all init functions. Override this function to perform initialization tasks that must be done prior to init 
  155. */ 
  156. public function pre_init() { 
  157.  
  158. if ( $this->is_gravityforms_supported() ) { 
  159.  
  160. //Entry meta 
  161. if ( $this->method_is_overridden( 'get_entry_meta' ) ) { 
  162. add_filter( 'gform_entry_meta', array( $this, 'get_entry_meta' ), 10, 2 ); 
  163.  
  164. /** 
  165. * Plugin starting point. Handles hooks and loading of language files. 
  166. */ 
  167. public function init() { 
  168.  
  169. // Initializing translations. Translation files in the WP_LANG_DIR folder have a higher priority. 
  170. $locale = apply_filters( 'plugin_locale', get_locale(), $this->_slug ); 
  171. load_textdomain( $this->_slug, WP_LANG_DIR . '/gravityforms/' . $this->_slug . '-' . $locale . '.mo' ); 
  172. load_plugin_textdomain( $this->_slug, false, $this->_slug . '/languages' ); 
  173.  
  174. add_filter( 'gform_logging_supported', array( $this, 'set_logging_supported' ) ); 
  175.  
  176. if ( RG_CURRENT_PAGE == 'admin-ajax.php' ) { 
  177.  
  178. //If gravity forms is supported, initialize AJAX 
  179. if ( $this->is_gravityforms_supported() ) { 
  180. $this->init_ajax(); 
  181. } elseif ( is_admin() ) { 
  182.  
  183. $this->init_admin(); 
  184.  
  185. } else { 
  186.  
  187. if ( $this->is_gravityforms_supported() ) { 
  188. $this->init_frontend(); 
  189.  
  190.  
  191.  
  192. /** 
  193. * Override this function to add initialization code (i.e. hooks) for the admin site (WP dashboard) 
  194. */ 
  195. protected function init_admin() { 
  196.  
  197. // enqueues admin scripts 
  198. add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ), 10, 0 ); 
  199.  
  200. // message enforcing min version of Gravity Forms 
  201. if ( isset( $this->_min_gravityforms_version ) && RG_CURRENT_PAGE == 'plugins.php' && false === $this->_enable_rg_autoupgrade ) { 
  202. add_action( 'after_plugin_row_' . $this->_path, array( $this, 'plugin_row' ) ); 
  203.  
  204. // STOP HERE IF GRAVITY FORMS IS NOT SUPPORTED 
  205. if ( isset( $this->_min_gravityforms_version ) && ! $this->is_gravityforms_supported( $this->_min_gravityforms_version ) ) { 
  206. return; 
  207.  
  208. $this->setup(); 
  209.  
  210. // Add form settings only when there are form settings fields configured or form_settings() method is implemented 
  211. if ( self::has_form_settings_page() ) { 
  212. $this->form_settings_init(); 
  213.  
  214. // Add plugin page when there is a plugin page configured or plugin_page() method is implemented 
  215. if ( self::has_plugin_page() ) { 
  216. $this->plugin_page_init(); 
  217.  
  218. // Add addon settings page only when there are addon settings fields configured or settings_page() method is implemented 
  219. if ( self::has_plugin_settings_page() ) { 
  220. if ( $this->current_user_can_any( $this->_capabilities_settings_page ) ) { 
  221. $this->plugin_settings_init(); 
  222.  
  223. // creates the top level app left menu 
  224. if ( self::has_app_menu() ) { 
  225. if ( $this->current_user_can_any( $this->_capabilities_app_menu ) ) { 
  226. add_action( 'admin_menu', array( $this, 'create_app_menu' ) ); 
  227.  
  228.  
  229. // Members plugin integration 
  230. if ( self::has_members_plugin() ) { 
  231. add_filter( 'members_get_capabilities', array( $this, 'members_get_capabilities' ) ); 
  232.  
  233. // Results page 
  234. if ( $this->method_is_overridden( 'get_results_page_config' ) ) { 
  235. $results_page_config = $this->get_results_page_config(); 
  236. $results_capabilities = rgar( $results_page_config, 'capabilities' ); 
  237. if ( $results_page_config && $this->current_user_can_any( $results_capabilities ) ) { 
  238. $this->results_page_init( $results_page_config ); 
  239.  
  240. // Locking 
  241. if ( $this->method_is_overridden( 'get_locking_config' ) ) { 
  242. require_once( GFCommon::get_base_path() . '/includes/locking/class-gf-locking.php' ); 
  243. require_once( 'class-gf-addon-locking.php' ); 
  244. $config = $this->get_locking_config(); 
  245. new GFAddonLocking( $config, $this ); 
  246.  
  247. // No conflict scripts 
  248. add_filter( 'gform_noconflict_scripts', array( $this, 'register_noconflict_scripts' ) ); 
  249. add_filter( 'gform_noconflict_styles', array( $this, 'register_noconflict_styles' ) ); 
  250.  
  251.  
  252. /** 
  253. * Override this function to add initialization code (i.e. hooks) for the public (customer facing) site 
  254. */ 
  255. protected function init_frontend() { 
  256.  
  257. $this->setup(); 
  258.  
  259. add_filter( 'gform_preview_styles', array( $this, 'enqueue_preview_styles' ), 10, 2 ); 
  260. add_filter( 'gform_print_styles', array( $this, 'enqueue_print_styles' ), 10, 2 ); 
  261. add_action( 'gform_enqueue_scripts', array( $this, 'enqueue_scripts' ), 10, 2 ); 
  262.  
  263.  
  264. /** 
  265. * Override this function to add AJAX hooks or to add initialization code when an AJAX request is being performed 
  266. */ 
  267. protected function init_ajax() { 
  268. if ( rgpost( 'view' ) == 'gf_results_' . $this->_slug ) { 
  269. require_once( GFCommon::get_base_path() . '/tooltips.php' ); 
  270. require_once( 'class-gf-results.php' ); 
  271. $gf_results = new GFResults( $this->_slug, $this->get_results_page_config() ); 
  272. add_action( 'wp_ajax_gresults_get_results_gf_results_' . $this->_slug, array( $gf_results, 'ajax_get_results' ) ); 
  273. add_action( 'wp_ajax_gresults_get_more_results_gf_results_' . $this->_slug, array( $gf_results, 'ajax_get_more_results' ) ); 
  274. } elseif ( $this->method_is_overridden( 'get_locking_config' ) ) { 
  275. require_once( GFCommon::get_base_path() . '/includes/locking/class-gf-locking.php' ); 
  276. require_once( 'class-gf-addon-locking.php' ); 
  277. $config = $this->get_locking_config(); 
  278. new GFAddonLocking( $config, $this ); 
  279.  
  280.  
  281. //-------------- Setup --------------- 
  282.  
  283. /** 
  284. * 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. 
  285. */ 
  286. protected function setup() { 
  287.  
  288. //Upgrading add-on 
  289. $installed_version = get_option( 'gravityformsaddon_' . $this->_slug . '_version' ); 
  290.  
  291. //Making sure version has really changed. Gets around aggressive caching issue on some sites that cause setup to run multiple times. 
  292. if ( $installed_version != $this->_version ) { 
  293. $installed_version = GFForms::get_wp_option( 'gravityformsaddon_' . $this->_slug . '_version' ); 
  294.  
  295. //Upgrade if version has changed 
  296. if ( $installed_version != $this->_version ) { 
  297.  
  298. $this->upgrade( $installed_version ); 
  299. update_option( 'gravityformsaddon_' . $this->_slug . '_version', $this->_version ); 
  300.  
  301. /** 
  302. * Override this function to add to add database update scripts or any other code to be executed when the Add-On version changes 
  303. */ 
  304. protected function upgrade( $previous_version ) { 
  305. return; 
  306.  
  307.  
  308. //-------------- Script enqueuing --------------- 
  309.  
  310. /** 
  311. * Override this function to provide a list of styles to be enqueued. 
  312. * When overriding this function, be sure to call parent::styles() to ensure the base class scripts are enqueued. 
  313. * See scripts() for an example of the format expected to be returned. 
  314. */ 
  315. protected function styles() { 
  316. $min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG || isset( $_GET['gform_debug'] ) ? '' : '.min'; 
  317. return array( 
  318. array( 
  319. 'handle' => 'gaddon_form_settings_css',  
  320. 'src' => GFAddOn::get_gfaddon_base_url() . "/css/gaddon_settings{$min}.css",  
  321. 'version' => GFCommon::$version,  
  322. 'enqueue' => array( 
  323. array( 'admin_page' => array( 'form_settings', 'plugin_settings', 'plugin_page', 'app_settings' ) ),  
  324. ),  
  325. array( 
  326. 'handle' => 'gaddon_results_css',  
  327. 'src' => GFAddOn::get_gfaddon_base_url() . "/css/gaddon_results{$min}.css",  
  328. 'version' => GFCommon::$version,  
  329. 'enqueue' => array( 
  330. array( 'admin_page' => array( 'results' ) ),  
  331. ),  
  332. ); 
  333.  
  334.  
  335. /** 
  336. * Override this function to provide a list of scripts to be enqueued. 
  337. * When overriding this function, be sure to call parent::scripts() to ensure the base class scripts are enqueued. 
  338. * Following is an example of the array that is expected to be returned by this function: 
  339. *<pre> 
  340. * <code> 
  341. * array( 
  342. * array( "handle" => 'maskedinput',  
  343. * "src" => GFCommon::get_base_url() . '/js/jquery.maskedinput-1.3.min.js',  
  344. * "version" => GFCommon::$version,  
  345. * "deps" => array("jquery"),  
  346. * "in_footer" => false,  
  347. * //Determines where the script will be enqueued. The script will be enqueued if any of the conditions match 
  348. * "enqueue" => array( 
  349. * //admin_page - Specified one or more pages (known pages) where the script is supposed to be enqueued. 
  350. * //To enqueue scripts in the front end (public website), simply don't define this setting 
  351. * array("admin_page" => array("form_settings", 'plugin_settings') ),  
  352. * //tab - Specifies a form settings or plugin settings tab in which the script is supposed to be enqueued. If none is specified, the script will be enqueued in any of the form settings or plugin_settings page 
  353. * array("tab" => 'signature'),  
  354. * //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 
  355. * array("query" => 'page=gf_edit_forms&view=settings&id=_notempty_') 
  356. * //post - Specifies a set of post ($_POST) values. If all specified posted values match the current request, the script will be enqueued 
  357. * array("post" => 'posted_field=val') 
  358. * ) 
  359. * ),  
  360. * array( 
  361. * "handle" => 'super_signature_script',  
  362. * "src" => $this->get_base_url() . '/super_signature/ss.js',  
  363. * "version" => $this->_version,  
  364. * "deps" => array("jquery"),  
  365. * "callback" => array($this, 'localize_scripts'),  
  366. * "strings" => array( 
  367. * // Accessible in JavaScript using the global variable "[script handle]_strings" 
  368. * "stringKey1" => __("The string", 'gravityforms'),  
  369. * "stringKey2" => __("Another string.", 'gravityforms') 
  370. * ) 
  371. * "enqueue" => array( 
  372. * //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. 
  373. * array("field_types" => array("signature")) 
  374. * ) 
  375. * ) 
  376. * ); 
  377. * </code> 
  378. * </pre> 
  379. */ 
  380. protected function scripts() { 
  381. $min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG || isset( $_GET['gform_debug'] ) ? '' : '.min'; 
  382. return array( 
  383. array( 
  384. 'handle' => 'gform_form_admin',  
  385. 'enqueue' => array( array( 'admin_page' => array( 'form_settings' ) ) ) 
  386. ),  
  387. array( 
  388. 'handle' => 'gform_gravityforms',  
  389. 'enqueue' => array( array( 'admin_page' => array( 'form_settings' ) ) ) 
  390. ),  
  391. array( 
  392. 'handle' => 'google_charts',  
  393. 'src' => 'https://www.google.com/jsapi',  
  394. 'version' => GFCommon::$version,  
  395. 'enqueue' => array( 
  396. array( 'admin_page' => array( 'results' ) ),  
  397. ),  
  398. array( 
  399. 'handle' => 'gaddon_results_js',  
  400. 'src' => GFAddOn::get_gfaddon_base_url() . "/js/gaddon_results{$min}.js",  
  401. 'version' => GFCommon::$version,  
  402. 'deps' => array( 'jquery', 'sack', 'jquery-ui-resizable', 'gform_datepicker_init', 'google_charts', 'gform_field_filter' ),  
  403. 'callback' => array( 'GFResults', 'localize_results_scripts' ),  
  404. 'enqueue' => array( 
  405. array( 'admin_page' => array( 'results' ) ),  
  406. ),  
  407. array( 
  408. 'handle' => 'gaddon_repeater',  
  409. 'src' => GFAddOn::get_gfaddon_base_url() . "/js/repeater{$min}.js",  
  410. 'version' => GFCommon::$version,  
  411. 'deps' => array( 'jquery' ),  
  412. 'enqueue' => array( 
  413. array( 
  414. 'admin_page' => array( 'form_settings' ),  
  415. ),  
  416. ),  
  417. ),  
  418. array( 
  419. 'handle' => 'gaddon_fieldmap_js',  
  420. 'src' => GFAddOn::get_gfaddon_base_url() . "/js/gaddon_fieldmap{$min}.js",  
  421. 'version' => GFCommon::$version,  
  422. 'deps' => array( 'jquery', 'gaddon_repeater' ),  
  423. 'enqueue' => array( 
  424. array( 'admin_page' => array( 'form_settings' ) ),  
  425. ),  
  426. array( 
  427. 'handle' => 'gaddon_selectcustom_js',  
  428. 'src' => GFAddOn::get_gfaddon_base_url() . "/js/gaddon_selectcustom{$min}.js",  
  429. 'version' => GFCommon::$version,  
  430. 'deps' => array( 'jquery' ),  
  431. 'enqueue' => array( 
  432. array( 'admin_page' => array( 'form_settings' ) ),  
  433. ),  
  434. ); 
  435.  
  436.  
  437. /** 
  438. * Target of admin_enqueue_scripts and gform_enqueue_scripts hooks. 
  439. * Not intended to be overridden by child classes. 
  440. * In order to enqueue scripts and styles, override the scripts() and styles() functions 
  441. * @ignore 
  442. */ 
  443. public function enqueue_scripts( $form = '', $is_ajax = false ) { 
  444.  
  445. if ( empty( $form ) ) { 
  446. $form = $this->get_current_form(); 
  447.  
  448. //Enqueueing scripts 
  449. $scripts = $this->scripts(); 
  450. foreach ( $scripts as $script ) { 
  451. $src = isset( $script['src'] ) ? $script['src'] : false; 
  452. $deps = isset( $script['deps'] ) ? $script['deps'] : array(); 
  453. $version = isset( $script['version'] ) ? $script['version'] : false; 
  454. $in_footer = isset( $script['in_footer'] ) ? $script['in_footer'] : false; 
  455. wp_register_script( $script['handle'], $src, $deps, $version, $in_footer ); 
  456. if ( isset( $script['enqueue'] ) && $this->_can_enqueue_script( $script['enqueue'], $form, $is_ajax ) ) { 
  457. $this->add_no_conflict_scripts( array( $script['handle'] ) ); 
  458. wp_enqueue_script( $script['handle'] ); 
  459. if ( isset( $script['strings'] ) ) { 
  460. wp_localize_script( $script['handle'], $script['handle'] . '_strings', $script['strings'] ); 
  461. if ( isset( $script['callback'] ) && is_callable( $script['callback'] ) ) { 
  462. $args = compact( 'form', 'is_ajax' ); 
  463. call_user_func_array( $script['callback'], $args ); 
  464.  
  465. //Enqueueing styles 
  466. $styles = $this->styles(); 
  467. foreach ( $styles as $style ) { 
  468. $src = isset( $style['src'] ) ? $style['src'] : false; 
  469. $deps = isset( $style['deps'] ) ? $style['deps'] : array(); 
  470. $version = isset( $style['version'] ) ? $style['version'] : false; 
  471. $media = isset( $style['media'] ) ? $style['media'] : 'all'; 
  472. wp_register_style( $style['handle'], $src, $deps, $version, $media ); 
  473. if ( $this->_can_enqueue_script( $style['enqueue'], $form, $is_ajax ) ) { 
  474. $this->add_no_conflict_styles( array( $style['handle'] ) ); 
  475. if ( $this->is_preview() ) { 
  476. $this->_preview_styles[] = $style['handle']; 
  477. } elseif ( $this->is_print() ) { 
  478. $this->_print_styles[] = $style['handle']; 
  479. } else { 
  480. wp_enqueue_style( $style['handle'] ); 
  481.  
  482. /** 
  483. * Target of gform_preview_styles. Enqueue styles to the preview page. 
  484. * Not intended to be overridden by child classes 
  485. * @ignore 
  486. */ 
  487. public function enqueue_preview_styles( $preview_styles, $form ) { 
  488. return array_merge( $preview_styles, $this->_preview_styles ); 
  489.  
  490.  
  491. /** 
  492. * Target of gform_print_styles. Enqueue styles to the print entry page. 
  493. * Not intended to be overridden by child classes 
  494. * @ignore 
  495. */ 
  496. public function enqueue_print_styles( $print_styles, $form ) { 
  497. if ( false === $print_styles ) { 
  498. $print_styles = array(); 
  499.  
  500. $styles = $this->styles(); 
  501. foreach ( $styles as $style ) { 
  502. if ( $this->_can_enqueue_script( $style['enqueue'], $form, false ) ) { 
  503. $this->add_no_conflict_styles( array( $style['handle'] ) ); 
  504. $src = isset( $style['src'] ) ? $style['src'] : false; 
  505. $deps = isset( $style['deps'] ) ? $style['deps'] : array(); 
  506. $version = isset( $style['version'] ) ? $style['version'] : false; 
  507. $media = isset( $style['media'] ) ? $style['media'] : 'all'; 
  508. wp_register_style( $style['handle'], $src, $deps, $version, $media ); 
  509. $print_styles[] = $style['handle']; 
  510.  
  511. return array_merge( $print_styles, $this->_print_styles ); 
  512.  
  513.  
  514. /** 
  515. * Adds scripts to the list of white-listed no conflict scripts. 
  516. * @param $scripts 
  517. */ 
  518. private function add_no_conflict_scripts( $scripts ) { 
  519. $this->_no_conflict_scripts = array_merge( $scripts, $this->_no_conflict_scripts ); 
  520.  
  521.  
  522. /** 
  523. * Adds styles to the list of white-listed no conflict styles. 
  524. * @param $styles 
  525. */ 
  526. private function add_no_conflict_styles( $styles ) { 
  527. $this->_no_conflict_styles = array_merge( $styles, $this->_no_conflict_styles ); 
  528.  
  529. private function _can_enqueue_script( $enqueue_conditions, $form, $is_ajax ) { 
  530. if ( empty( $enqueue_conditions ) ) { 
  531. return false; 
  532.  
  533. foreach ( $enqueue_conditions as $condition ) { 
  534. if ( is_callable( $condition ) ) { 
  535. return call_user_func( $condition, $form, $is_ajax ); 
  536. } else { 
  537. $query_matches = isset( $condition['query'] ) ? $this->_request_condition_matches( $_GET, $condition['query'] ) : true; 
  538. $post_matches = isset( $condition['post'] ) ? $this->_request_condition_matches( $_POST, $condition['query'] ) : true; 
  539. $admin_page_matches = isset( $condition['admin_page'] ) ? $this->_page_condition_matches( $condition['admin_page'], rgar( $condition, 'tab' ) ) : true; 
  540. $field_type_matches = isset( $condition['field_types'] ) ? $this->_field_condition_matches( $condition['field_types'], $form ) : true; 
  541.  
  542. if ( $query_matches && $post_matches && $admin_page_matches && $field_type_matches ) { 
  543. return true; 
  544.  
  545. return false; 
  546.  
  547. private function _request_condition_matches( $request, $query ) { 
  548. parse_str( $query, $query_array ); 
  549. foreach ( $query_array as $key => $value ) { 
  550.  
  551. switch ( $value ) { 
  552. case '_notempty_' : 
  553. if ( rgempty( $key, $request ) ) { 
  554. return false; 
  555. break; 
  556. case '_empty_' : 
  557. if ( ! rgempty( $key, $request ) ) { 
  558. return false; 
  559. break; 
  560. default : 
  561. if ( rgar( $request, $key ) != $value ) { 
  562. return false; 
  563. break; 
  564.  
  565. return true; 
  566.  
  567. private function _page_condition_matches( $pages, $tab ) { 
  568. if ( ! is_array( $pages ) ) { 
  569. $pages = array( $pages ); 
  570.  
  571. foreach ( $pages as $page ) { 
  572. switch ( $page ) { 
  573. case 'form_editor' : 
  574. if ( $this->is_form_editor() ) { 
  575. return true; 
  576.  
  577. break; 
  578.  
  579. case 'form_settings' : 
  580. if ( $this->is_form_settings( $tab ) ) { 
  581. return true; 
  582.  
  583. break; 
  584.  
  585. case 'plugin_settings' : 
  586. if ( $this->is_plugin_settings( $tab ) ) { 
  587. return true; 
  588.  
  589. break; 
  590.  
  591. case 'app_settings' : 
  592. if ( $this->is_app_settings( $tab ) ) { 
  593. return true; 
  594.  
  595. break; 
  596.  
  597. case 'plugin_page' : 
  598. if ( $this->is_plugin_page() ) { 
  599. return true; 
  600.  
  601. break; 
  602.  
  603. case 'entry_list' : 
  604. if ( $this->is_entry_list() ) { 
  605. return true; 
  606.  
  607. break; 
  608.  
  609. case 'entry_view' : 
  610. if ( $this->is_entry_view() ) { 
  611. return true; 
  612.  
  613. break; 
  614.  
  615. case 'entry_edit' : 
  616. if ( $this->is_entry_edit() ) { 
  617. return true; 
  618.  
  619. break; 
  620.  
  621. case 'results' : 
  622. if ( $this->is_results() ) { 
  623. return true; 
  624.  
  625. break; 
  626.  
  627.  
  628. return false; 
  629.  
  630.  
  631. private function _field_condition_matches( $field_types, $form ) { 
  632. if ( ! is_array( $field_types ) ) { 
  633. $field_types = array( $field_types ); 
  634.  
  635. $fields = GFAPI::get_fields_by_type( $form, $field_types ); 
  636. if ( count( $fields ) > 0 ) { 
  637. return true; 
  638.  
  639. return false; 
  640.  
  641. /** 
  642. * Target for the gform_noconflict_scripts filter. Adds scripts to the list of white-listed no conflict scripts. 
  643. * Not intended to be overridden or called directed by Add-Ons. 
  644. * @ignore 
  645. * @param array $scripts Array of scripts to be white-listed 
  646. * @return array 
  647. */ 
  648. public function register_noconflict_scripts( $scripts ) { 
  649. //registering scripts with Gravity Forms so that they get enqueued when running in no-conflict mode 
  650. return array_merge( $scripts, $this->_no_conflict_scripts ); 
  651.  
  652. /** 
  653. * Target for the gform_noconflict_styles filter. Adds styles to the list of white-listed no conflict scripts. 
  654. * Not intended to be overridden or called directed by Add-Ons. 
  655. * @ignore 
  656. * @param array $styles Array of styles to be white-listed 
  657. * @return array 
  658. */ 
  659. public function register_noconflict_styles( $styles ) { 
  660. //registering styles with Gravity Forms so that they get enqueued when running in no-conflict mode 
  661. return array_merge( $styles, $this->_no_conflict_styles ); 
  662.  
  663.  
  664.  
  665. //-------------- Entry meta -------------------------------------- 
  666.  
  667. /** 
  668. * Override this method to activate and configure entry meta. 
  669. * @param array $entry_meta An array of entry meta already registered with the gform_entry_meta filter. 
  670. * @param int $form_id The form id 
  671. * @return array The filtered entry meta array. 
  672. */ 
  673. protected function get_entry_meta( $entry_meta, $form_id ) { 
  674. return $entry_meta; 
  675.  
  676.  
  677. //-------------- Results page -------------------------------------- 
  678. /** 
  679. * Returns the configuration for the results page. By default this is not activated. 
  680. * To activate the results page override this function and return an array with the configuration data. 
  681. * Example: 
  682. * public function get_results_page_config() { 
  683. * return array( 
  684. * "title" => 'Quiz Results',  
  685. * "capabilities" => array("gravityforms_quiz_results"),  
  686. * "callbacks" => array( 
  687. * "fields" => array($this, 'results_fields'),  
  688. * "calculation" => array($this, 'results_calculation'),  
  689. * "markup" => array($this, 'results_markup'),  
  690. * ) 
  691. * ); 
  692. * } 
  693. */ 
  694. public function get_results_page_config() { 
  695. return false; 
  696.  
  697. /** 
  698. * Initializes the result page functionality. To activate result page functionality, override the get_results_page_config() function. 
  699. * @param $results_page_config - configuration returned by get_results_page_config() 
  700. */ 
  701. protected function results_page_init( $results_page_config ) { 
  702. require_once( 'class-gf-results.php' ); 
  703.  
  704. if ( isset( $results_page_config['callbacks']['filters'] ) ) { 
  705. add_filter( 'gform_filters_pre_results', $results_page_config['callbacks']['filters'], 10, 2 ); 
  706.  
  707. if ( isset( $results_page_config['callbacks']['filter_ui'] ) ) { 
  708. add_filter( 'gform_filter_ui', $results_page_config['callbacks']['filter_ui'], 10, 5 ); 
  709.  
  710. $gf_results = new GFResults( $this->_slug, $results_page_config ); 
  711. $gf_results->init(); 
  712.  
  713. //-------------- Logging integration -------------------------------------- 
  714.  
  715. public function set_logging_supported( $plugins ) { 
  716. $plugins[ $this->_slug ] = $this->_title; 
  717.  
  718. return $plugins; 
  719.  
  720.  
  721. //-------------- Members plugin integration -------------------------------------- 
  722.  
  723. /** 
  724. * Checks whether the Members plugin is installed and activated. 
  725. * Not intended to be overridden or called directly by Add-Ons. 
  726. * @ignore 
  727. * @return bool 
  728. */ 
  729. protected function has_members_plugin() { 
  730. return function_exists( 'members_get_capabilities' ); 
  731.  
  732. /** 
  733. * Not intended to be overridden or called directly by Add-Ons. 
  734. * @ignore 
  735. * @param $caps 
  736. * @return array 
  737. */ 
  738. public function members_get_capabilities( $caps ) { 
  739. return array_merge( $caps, $this->_capabilities ); 
  740.  
  741. //-------------- Permissions: Capabilities and Roles ---------------------------- 
  742.  
  743. /** 
  744. * Checks whether the current user is assigned to a capability or role. 
  745. * @param string|array $caps An string or array of capabilities to check 
  746. * @return bool Returns true if the current user is assigned to any of the capabilities. 
  747. */ 
  748. protected function current_user_can_any( $caps ) { 
  749. return GFCommon::current_user_can_any( $caps ); 
  750.  
  751.  
  752. //------- Settings Helper Methods (Common to all settings pages) ------------------- 
  753.  
  754. /*** 
  755. * Renders the UI of all settings page based on the specified configuration array $sections 
  756. * @param array $sections - Configuration array containing all fields to be rendered grouped into sections 
  757. */ 
  758. protected function render_settings( $sections ) { 
  759.  
  760. if ( ! $this->has_setting_field_type( 'save', $sections ) ) { 
  761. $sections = $this->add_default_save_button( $sections ); 
  762.  
  763. ?> 
  764.  
  765. <form id="gform-settings" action="" method="post"> 
  766. <?php wp_nonce_field( $this->_slug . '_save_settings', '_' . $this->_slug . '_save_settings_nonce' ) ?> 
  767. <?php $this->settings( $sections ); ?> 
  768.  
  769. </form> 
  770.  
  771. <?php 
  772.  
  773. /*** 
  774. * Renders settings fields based on the specified configuration array $sections 
  775. * @param array $sections - Configuration array containing all fields to be rendered grouped into sections 
  776. */ 
  777. protected function settings( $sections ) { 
  778. $is_first = true; 
  779. foreach ( $sections as $section ) { 
  780. if ( $this->setting_dependency_met( rgar( $section, 'dependency' ) ) ) { 
  781. $this->single_section( $section, $is_first ); 
  782.  
  783. $is_first = false; 
  784.  
  785. /*** 
  786. * Displays the UI for a field section 
  787. * @param array $section - The section to be displayed 
  788. * @param bool $is_first - true for the first section in the list, false for all others 
  789. */ 
  790. protected function single_section( $section, $is_first = false ) { 
  791.  
  792. extract( 
  793. wp_parse_args( 
  794. $section, array( 
  795. 'title' => false,  
  796. 'description' => false,  
  797. 'id' => '',  
  798. 'class' => false,  
  799. 'style' => '',  
  800. 'tooltip' => false,  
  801. 'tooltip_class' => '' 
  802. ); 
  803.  
  804. $classes = array( 'gaddon-section' ); 
  805.  
  806. if ( $is_first ) { 
  807. $classes[] = 'gaddon-first-section'; 
  808.  
  809. if ( $class ) 
  810. $classes[] = $class; 
  811.  
  812. ?> 
  813.  
  814. <div 
  815. id="<?php echo $id; ?>" 
  816. class="<?php echo implode( ' ', $classes ); ?>" 
  817. style="<?php echo $style; ?>" 
  818.  
  819. <?php if ( $title ): ?> 
  820. <h4 class="gaddon-section-title gf_settings_subgroup_title"> 
  821. <?php echo $title; ?> 
  822. <?php if( $tooltip ): ?> 
  823. <?php gform_tooltip( $tooltip, $tooltip_class ); ?> 
  824. <?php endif; ?> 
  825. </h4> 
  826. <?php endif; ?> 
  827.  
  828. <?php if ( $description ): ?> 
  829. <div class="gaddon-section-description"><?php echo $description; ?></div> 
  830. <?php endif; ?> 
  831.  
  832. <table class="form-table gforms_form_settings"> 
  833.  
  834. <?php 
  835. foreach ( $section['fields'] as $field ) { 
  836.  
  837. if ( ! $this->setting_dependency_met( rgar( $field, 'dependency' ) ) ) 
  838. continue; 
  839.  
  840. if ( is_callable( array( $this, "single_setting_row_{$field['type']}" ) ) ) { 
  841. call_user_func( array( $this, "single_setting_row_{$field['type']}" ), $field ); 
  842. } else { 
  843. $this->single_setting_row( $field ); 
  844. ?> 
  845.  
  846. </table> 
  847.  
  848. </div> 
  849.  
  850. <?php 
  851.  
  852. /*** 
  853. * Displays the UI for the field container row 
  854. * @param array $field - The field to be displayed 
  855. */ 
  856. protected function single_setting_row( $field ) { 
  857.  
  858. $display = rgar( $field, 'hidden' ) || rgar( $field, 'type' ) == 'hidden' ? 'style="display:none;"' : ''; 
  859.  
  860. ?> 
  861.  
  862. <tr id="gaddon-setting-row-<?php echo $field['name'] ?>" <?php echo $display; ?>> 
  863. <th> 
  864. <?php $this->single_setting_label( $field ); ?> 
  865. </th> 
  866. <td> 
  867. <?php $this->single_setting( $field ); ?> 
  868. </td> 
  869. </tr> 
  870.  
  871. <?php 
  872.  
  873. /** 
  874. * Displays the label for a field, including the tooltip and requirement indicator. 
  875. */ 
  876. protected function single_setting_label( $field ) { 
  877.  
  878. echo $field['label']; 
  879.  
  880. if ( isset( $field['tooltip'] ) ) { 
  881. echo ' ' . gform_tooltip( $field['tooltip'], rgar( $field, 'tooltip_class' ), true ); 
  882.  
  883. if ( rgar( $field, 'required' ) ) { 
  884. echo ' ' . $this->get_required_indicator( $field ); 
  885.  
  886.  
  887. protected function single_setting_row_save( $field ) { 
  888. ?> 
  889.  
  890. <tr> 
  891. <td colspan="2"> 
  892. <?php $this->single_setting( $field ); ?> 
  893. </td> 
  894. </tr> 
  895.  
  896. <?php 
  897.  
  898. /*** 
  899. * Calls the appropriate field function to handle rendering of each specific field type 
  900. * @param array $field - The field to be rendered 
  901. */ 
  902. protected function single_setting( $field ) { 
  903. if ( is_callable( rgar( $field, 'callback' ) ) ) { 
  904. call_user_func( $field['callback'], $field ); 
  905. } elseif ( is_callable( array( $this, "settings_{$field['type']}" ) ) ) { 
  906. call_user_func( array( $this, "settings_{$field['type']}" ), $field ); 
  907. } else { 
  908. printf( esc_html__( "Field type '%s' has not been implemented", 'gravityforms' ), esc_html( $field['type'] ) ); 
  909.  
  910. /*** 
  911. * Sets the current saved settings to a class variable so that it can be accessed by lower level functions in order to initialize inputs with the appropriate values 
  912. * @param array $settings : Settings to be saved 
  913. */ 
  914. protected function set_settings( $settings ) { 
  915. $this->_saved_settings = $settings; 
  916.  
  917. /*** 
  918. * Sets the previous settings to a class variable so that it can be accessed by lower level functions providing support for 
  919. * verifying whether a value was changed before executing an action 
  920. * @param array $settings : Settings to be stored 
  921. */ 
  922. protected function set_previous_settings( $settings ) { 
  923. $this->_previous_settings = $settings; 
  924.  
  925. protected function get_previous_settings() { 
  926. return $this->_previous_settings; 
  927.  
  928.  
  929. /*** 
  930. * Gets settings from $_POST variable, returning a name/value collection of setting name and setting value 
  931. */ 
  932. protected function get_posted_settings() { 
  933. global $_gaddon_posted_settings; 
  934.  
  935. if ( isset( $_gaddon_posted_settings ) ) { 
  936. return $_gaddon_posted_settings; 
  937.  
  938. $_gaddon_posted_settings = array(); 
  939. if ( count( $_POST ) > 0 ) { 
  940. foreach ( $_POST as $key => $value ) { 
  941. if ( preg_match( '|_gaddon_setting_(.*)|', $key, $matches ) ) { 
  942. $_gaddon_posted_settings[ $matches[1] ] = self::maybe_decode_json( stripslashes_deep( $value ) ); 
  943.  
  944. return $_gaddon_posted_settings; 
  945.  
  946. protected static function maybe_decode_json( $value ) { 
  947. if ( self::is_json( $value ) ) { 
  948. return json_decode( $value, ARRAY_A ); 
  949.  
  950. return $value; 
  951.  
  952. protected static function is_json( $value ) { 
  953. if ( is_string( $value ) && in_array( substr( $value, 0, 1 ), array( '{', '[' ) ) && is_array( json_decode( $value, ARRAY_A ) ) ) { 
  954. return true; 
  955.  
  956. return false; 
  957.  
  958. /*** 
  959. * Gets the "current" settings, which are settings from $_POST variables if this is a postback request, or the current saved settings for a get request. 
  960. */ 
  961. protected function get_current_settings() { 
  962. //try getting settings from post 
  963. $settings = $this->get_posted_settings(); 
  964.  
  965. //if nothing has been posted, get current saved settings 
  966. if ( empty( $settings ) ) { 
  967. $settings = $this->_saved_settings; 
  968.  
  969. return $settings; 
  970.  
  971. /*** 
  972. * Retrieves the setting for a specific field/input 
  973. * @param string $setting_name The field or input name 
  974. * @param string $default_value Optional. The default value 
  975. * @param bool|array $settings Optional. THe settings array 
  976. * @return string|array 
  977. */ 
  978. protected function get_setting( $setting_name, $default_value = '', $settings = false ) { 
  979.  
  980. if ( ! $settings ) { 
  981. $settings = $this->get_current_settings(); 
  982.  
  983. if ( false === $settings ) { 
  984. return $default_value; 
  985.  
  986. if ( strpos( $setting_name, '[' ) !== false ) { 
  987. $path_parts = explode( '[', $setting_name ); 
  988. foreach ( $path_parts as $part ) { 
  989. $part = trim( $part, ']' ); 
  990. if ( $part != '0') { 
  991. if ( empty( $part ) ) { 
  992. return $settings; 
  993. if ( false === isset( $settings[ $part ] ) ) { 
  994. return $default_value; 
  995.  
  996. $settings = rgar( $settings, $part ); 
  997. $setting = $settings; 
  998. } else { 
  999. if ( false === isset( $settings[ $setting_name ] ) ) { 
  1000. return $default_value; 
  1001. $setting = $settings[ $setting_name ]; 
  1002.  
  1003. return $setting; 
  1004.  
  1005. /*** 
  1006. * Determines if a dependent field has been populated. 
  1007. * @param string $dependency - Field or input name of the "parent" field. 
  1008. * @return bool - true if the "parent" field has been filled out and false if it has not. 
  1009. */ 
  1010. protected function setting_dependency_met( $dependency ) { 
  1011.  
  1012. // if no dependency, always return true 
  1013. if ( ! $dependency ) { 
  1014. return true; 
  1015.  
  1016. //use a callback if one is specified in the configuration 
  1017. if ( is_callable( $dependency ) ) { 
  1018. return call_user_func( $dependency ); 
  1019.  
  1020. if ( is_array( $dependency ) ) { 
  1021. //supports: 'dependency' => array("field" => 'myfield', 'values' => array("val1", 'val2')) 
  1022. $dependency_field = $dependency['field']; 
  1023. $dependency_value = $dependency['values']; 
  1024. } else { 
  1025. //supports: 'dependency' => 'myfield' 
  1026. $dependency_field = $dependency; 
  1027. $dependency_value = '_notempty_'; 
  1028.  
  1029. if ( ! is_array( $dependency_value ) ) { 
  1030. $dependency_value = array( $dependency_value ); 
  1031.  
  1032. $current_value = $this->get_setting( $dependency_field ); 
  1033.  
  1034. foreach ( $dependency_value as $val ) { 
  1035. if ( $current_value == $val ) { 
  1036. return true; 
  1037.  
  1038. if ( $val == '_notempty_' && ! rgblank( $current_value ) ) { 
  1039. return true; 
  1040.  
  1041. return false; 
  1042.  
  1043. protected function has_setting_field_type( $type, $fields ) { 
  1044. if ( ! empty( $fields ) ) { 
  1045. foreach ( $fields as &$section ) { 
  1046. foreach ( $section['fields'] as $field ) { 
  1047. if ( rgar( $field, 'type' ) == $type ) { 
  1048. return true; 
  1049. return false; 
  1050.  
  1051. protected function add_default_save_button( $sections ) { 
  1052. $sections[ count( $sections ) - 1 ]['fields'][] = array( 'type' => 'save' ); 
  1053.  
  1054. return $sections; 
  1055.  
  1056. protected function get_save_success_message( $sections ) { 
  1057. $save_button = $this->get_save_button( $sections ); 
  1058.  
  1059. return isset( $save_button['messages']['success'] ) ? $save_button['messages']['success'] : esc_html__( 'Settings updated', 'gravityforms' ); 
  1060.  
  1061. protected function get_save_error_message( $sections ) { 
  1062. $save_button = $this->get_save_button( $sections ); 
  1063.  
  1064. return isset( $save_button['messages']['error'] ) ? $save_button['messages']['error'] : esc_html__( 'There was an error while saving your settings', 'gravityforms' ); 
  1065.  
  1066. protected function get_save_button( $sections ) { 
  1067. $fields = $sections[ count( $sections ) - 1 ]['fields']; 
  1068.  
  1069. foreach ( $fields as $field ) { 
  1070. if ( $field['type'] == 'save' ) 
  1071. return $field; 
  1072.  
  1073. return false; 
  1074.  
  1075.  
  1076.  
  1077. //------------- Field Types ------------------------------------------------------ 
  1078.  
  1079. /*** 
  1080. * Renders and initializes a text field based on the $field array 
  1081. * @param array $field - Field array containing the configuration options of this field 
  1082. * @param bool $echo = true - true to echo the output to the screen, false to simply return the contents as a string 
  1083. * @return string The HTML for the field 
  1084. */ 
  1085. protected function settings_text( $field, $echo = true ) { 
  1086.  
  1087. $field['type'] = 'text'; //making sure type is set to text 
  1088. $field['input_type'] = rgar( $field, 'input_type' ) ? rgar( $field, 'input_type' ) : 'text'; 
  1089. $attributes = $this->get_field_attributes( $field ); 
  1090. $default_value = rgar( $field, 'value' ) ? rgar( $field, 'value' ) : rgar( $field, 'default_value' ); 
  1091. $value = $this->get_setting( $field['name'], $default_value ); 
  1092.  
  1093.  
  1094. $name = esc_attr( $field['name'] ); 
  1095. $tooltip = isset( $choice['tooltip'] ) ? gform_tooltip( $choice['tooltip'], rgar( $choice, 'tooltip_class' ), true ) : ''; 
  1096. $html = ''; 
  1097.  
  1098. $html .= '<input 
  1099. type="' . esc_attr( $field['input_type'] ) . '" 
  1100. name="_gaddon_setting_' . esc_attr( $field['name'] ) . '" 
  1101. value="' . esc_attr( $value ) . '" ' . 
  1102. implode( ' ', $attributes ) . 
  1103. ' />'; 
  1104.  
  1105. $html .= rgar( $field, 'after_input' ); 
  1106.  
  1107. $feedback_callback = rgar( $field, 'feedback_callback' ); 
  1108. if ( is_callable( $feedback_callback ) ) { 
  1109. $is_valid = call_user_func_array( $feedback_callback, array( $value, $field ) ); 
  1110. $icon = ''; 
  1111. if ( $is_valid === true ) { 
  1112. $icon = 'icon-check fa-check gf_valid'; // check icon 
  1113. } elseif ( $is_valid === false ) { 
  1114. $icon = 'icon-remove fa-times gf_invalid'; // x icon 
  1115.  
  1116. if ( ! empty( $icon ) ) { 
  1117. $html .= "  <i class=\"fa {$icon}\"></i>"; 
  1118.  
  1119. if ( $this->field_failed_validation( $field ) ) { 
  1120. $html .= $this->get_error_icon( $field ); 
  1121.  
  1122. if ( $echo ) { 
  1123. echo $html; 
  1124.  
  1125. return $html; 
  1126.  
  1127. /*** 
  1128. * Renders and initializes a textarea field based on the $field array 
  1129. * @param array $field - Field array containing the configuration options of this field 
  1130. * @param bool $echo = true - true to echo the output to the screen, false to simply return the contents as a string 
  1131. * @return string The HTML for the field 
  1132. */ 
  1133. protected function settings_textarea( $field, $echo = true ) { 
  1134. $field['type'] = 'textarea'; //making sure type is set to textarea 
  1135. $attributes = $this->get_field_attributes( $field ); 
  1136. $default_value = rgar( $field, 'value' ) ? rgar( $field, 'value' ) : rgar( $field, 'default_value' ); 
  1137. $value = $this->get_setting( $field['name'], $default_value ); 
  1138.  
  1139. $name = '' . esc_attr( $field['name'] ); 
  1140. $tooltip = isset( $choice['tooltip'] ) ? gform_tooltip( $choice['tooltip'], rgar( $choice, 'tooltip_class' ), true ) : ''; 
  1141. $html = ''; 
  1142.  
  1143. if ( rgar( $field, 'use_editor' ) && GFCommon::is_wp_version( '3.3' ) ) { 
  1144.  
  1145. $html .= '<span class="mt-gaddon-editor mt-_gaddon_setting_'. $field['name'] .'"></span>'; 
  1146.  
  1147. ob_start(); 
  1148.  
  1149. wp_editor( $value, '_gaddon_setting_'. $field['name'], array( 'autop' => false, 'editor_class' => 'merge-tag-support mt-wp_editor mt-manual_position mt-position-right' ) ); 
  1150.  
  1151. $html .= ob_get_contents(); 
  1152. ob_end_clean(); 
  1153.  
  1154. } else { 
  1155.  
  1156. $html .= '<textarea 
  1157. name="_gaddon_setting_' . $name . '" ' . 
  1158. implode( ' ', $attributes ) . 
  1159. '>' . 
  1160. esc_html( $value ) . 
  1161. '</textarea>'; 
  1162.  
  1163.  
  1164. if ( $this->field_failed_validation( $field ) ) { 
  1165. $html .= $this->get_error_icon( $field ); 
  1166.  
  1167. if ( $echo ) { 
  1168. echo $html; 
  1169.  
  1170. return $html; 
  1171.  
  1172.  
  1173. /*** 
  1174. * Renders and initializes a hidden field based on the $field array 
  1175. * @param array $field - Field array containing the configuration options of this field 
  1176. * @param bool $echo = true - true to echo the output to the screen, false to simply return the contents as a string 
  1177. * @return string The HTML for the field 
  1178. */ 
  1179. protected function settings_hidden( $field, $echo = true ) { 
  1180. $field['type'] = 'hidden'; //making sure type is set to hidden 
  1181. $attributes = $this->get_field_attributes( $field ); 
  1182.  
  1183. $default_value = rgar( $field, 'value' ) ? rgar( $field, 'value' ) : rgar( $field, 'default_value' ); 
  1184. $value = $this->get_setting( $field['name'], $default_value ); 
  1185.  
  1186. if ( is_array( $value ) ) { 
  1187. $value = json_encode( $value ); 
  1188.  
  1189. $html = '<input 
  1190. type="hidden" 
  1191. name="_gaddon_setting_' . esc_attr( $field['name'] ) . '" 
  1192. value=\'' . esc_attr( $value ) . '\' ' . 
  1193. implode( ' ', $attributes ) . 
  1194. ' />'; 
  1195.  
  1196. if ( $echo ) { 
  1197. echo $html; 
  1198.  
  1199. return $html; 
  1200.  
  1201. /*** 
  1202. * Renders and initializes a checkbox field or a collection of checkbox fields based on the $field array 
  1203. * @param array $field - Field array containing the configuration options of this field 
  1204. * @param bool $echo = true - true to echo the output to the screen, false to simply return the contents as a string 
  1205. * @return string The HTML for the field 
  1206. */ 
  1207. protected function settings_checkbox( $field, $echo = true ) { 
  1208.  
  1209. $field['type'] = 'checkbox'; //making sure type is set to checkbox 
  1210.  
  1211. $field_attributes = $this->get_field_attributes( $field, array() ); 
  1212. $horizontal = rgar( $field, 'horizontal' ) ? ' gaddon-setting-inline' : ''; 
  1213.  
  1214.  
  1215.  
  1216. $html = ''; 
  1217. $default_choice_attributes = array( 'onclick' => 'jQuery(this).siblings("input[type=hidden]").val(jQuery(this).prop("checked") ? 1 : 0);' ); 
  1218. $is_first_choice = true; 
  1219. if ( is_array( $field['choices'] ) ) { 
  1220. foreach ( $field['choices'] as $choice ) { 
  1221. $choice['id'] = sanitize_title( $choice['name'] ); 
  1222. $choice_attributes = $this->get_choice_attributes( $choice, $field_attributes, $default_choice_attributes ); 
  1223. $value = $this->get_setting( $choice['name'], rgar( $choice, 'default_value' ) ); 
  1224. $tooltip = isset( $choice['tooltip'] ) ? gform_tooltip( $choice['tooltip'], rgar( $choice, 'tooltip_class' ), true ) : ''; 
  1225.  
  1226. //displaying error message after first checkbox item 
  1227. $error_icon = ''; 
  1228. if ( $is_first_choice ) { 
  1229. $error_icon = $this->field_failed_validation( $field ) ? $this->get_error_icon( $field ) : ''; 
  1230.  
  1231. $html .= $this->checkbox_item( $choice, $horizontal, $choice_attributes, $value, $tooltip, $error_icon ); 
  1232.  
  1233. $is_first_choice = false; 
  1234.  
  1235. if ( $echo ) { 
  1236. echo $html; 
  1237.  
  1238. return $html; 
  1239.  
  1240.  
  1241. /** 
  1242. * Returns the markup for an individual checkbox item give the parameters 
  1243. * @param $choice - Choice array with all configured properties 
  1244. * @param $horizontal_class - CSS class to style checkbox items horizontally 
  1245. * @param $attributes - String containing all the attributes for the input tag. 
  1246. * @param $value - Currently selection (1 if field has been checked. 0 or null otherwise) 
  1247. * @param $tooltip - String containing a tooltip for this checkbox item. 
  1248. * @return string - The markup of an individual checkbox item 
  1249. */ 
  1250. protected function checkbox_item( $choice, $horizontal_class, $attributes, $value, $tooltip, $error_icon='' ) { 
  1251. $hidden_field_value = $value == '1' ? '1' : '0'; 
  1252. $checkbox_item = ' 
  1253. <div id="gaddon-setting-checkbox-choice-' . $choice['id'] . '" class="gaddon-setting-checkbox' . $horizontal_class . '"> 
  1254. <input type=hidden name="_gaddon_setting_' . esc_attr( $choice['name'] ) . '" value="' . $hidden_field_value . '" />'; 
  1255.  
  1256. if ( is_callable( array( $this, "checkbox_input_{$choice['name']}" ) ) ) { 
  1257. $markup = call_user_func( array( $this, "checkbox_input_{$choice['name']}" ), $choice, $attributes, $value, $tooltip ); 
  1258. } else { 
  1259. $markup = $this->checkbox_input( $choice, $attributes, $value, $tooltip ); 
  1260.  
  1261. $checkbox_item .= $markup . $error_icon . '</div>'; 
  1262.  
  1263. return $checkbox_item; 
  1264.  
  1265. /** 
  1266. * Returns the markup for an individual checkbox input and its associated label 
  1267. * @param $choice - Choice array with all configured properties 
  1268. * @param $attributes - String containing all the attributes for the input tag. 
  1269. * @param $value - Currently selection (1 if field has been checked. 0 or null otherwise) 
  1270. * @param $tooltip - String containing a tooltip for this checkbox item. 
  1271. * @return string - The markup of an individual checkbox input and its associated label 
  1272. */ 
  1273. protected function checkbox_input( $choice, $attributes, $value, $tooltip ) { 
  1274. $markup = '<input type = "checkbox" ' . 
  1275. implode( ' ', $attributes ) . ' ' . 
  1276. checked( $value, '1', false ) . 
  1277. ' /> 
  1278. <label for="' . esc_attr( $choice['id'] ) . '">' . esc_html( $choice['label'] ) . ' ' . $tooltip . '</label>'; 
  1279.  
  1280. return $markup; 
  1281.  
  1282.  
  1283. /*** 
  1284. * Renders and initializes a radio field or a collection of radio fields based on the $field array 
  1285. * @param array $field - Field array containing the configuration options of this field 
  1286. * @param bool $echo = true - true to echo the output to the screen, false to simply return the contents as a string 
  1287. * @return string Returns the markup for the radio buttons 
  1288. */ 
  1289. protected function settings_radio( $field, $echo = true ) { 
  1290.  
  1291. $field['type'] = 'radio'; //making sure type is set to radio 
  1292.  
  1293. $selected_value = $this->get_setting( $field['name'], rgar( $field, 'default_value' ) ); 
  1294. $field_attributes = $this->get_field_attributes( $field ); 
  1295. $horizontal = rgar( $field, 'horizontal' ) ? ' gaddon-setting-inline' : ''; 
  1296. $html = ''; 
  1297. if ( is_array( $field['choices'] ) ) { 
  1298. foreach ( $field['choices'] as $i => $choice ) { 
  1299. $choice['id'] = $field['name'] . $i; 
  1300. $choice_attributes = $this->get_choice_attributes( $choice, $field_attributes ); 
  1301.  
  1302. $tooltip = isset( $choice['tooltip'] ) ? gform_tooltip( $choice['tooltip'], rgar( $choice, 'tooltip_class' ), true ) : ''; 
  1303.  
  1304. $radio_value = isset( $choice['value'] ) ? $choice['value'] : $choice['label']; 
  1305. $checked = checked( $selected_value, $radio_value, false ); 
  1306. $html .= ' 
  1307. <div id="gaddon-setting-radio-choice-' . $choice['id'] . '" class="gaddon-setting-radio' . $horizontal . '"> 
  1308. <label for="' . esc_attr( $choice['id'] ) . '"> 
  1309. <input 
  1310. id = "' . esc_attr( $choice['id'] ) . '" 
  1311. type = "radio" ' . 
  1312. 'name="_gaddon_setting_' . esc_attr( $field['name'] ) . '" ' . 
  1313. 'value="' . $radio_value . '" ' . 
  1314. implode( ' ', $choice_attributes ) . ' ' . 
  1315. $checked . 
  1316. ' /><span>' . esc_html( $choice['label'] ) . ' ' . $tooltip . '</span> 
  1317. </label> 
  1318. </div> 
  1319. '; 
  1320.  
  1321. if ( $this->field_failed_validation( $field ) ) { 
  1322. $html .= $this->get_error_icon( $field ); 
  1323.  
  1324. if ( $echo ) { 
  1325. echo $html; 
  1326.  
  1327. return $html; 
  1328.  
  1329. /*** 
  1330. * Renders and initializes a drop down field based on the $field array 
  1331. * @param array $field - Field array containing the configuration options of this field 
  1332. * @param bool $echo = true - true to echo the output to the screen, false to simply return the contents as a string 
  1333. * @return string The HTML for the field 
  1334. */ 
  1335. protected function settings_select( $field, $echo = true ) { 
  1336.  
  1337. $field['type'] = 'select'; // making sure type is set to select 
  1338. $attributes = $this->get_field_attributes( $field ); 
  1339. $value = $this->get_setting( $field['name'], rgar( $field, 'default_value' ) ); 
  1340. $name = '' . esc_attr( $field['name'] ); 
  1341.  
  1342. $html = sprintf( 
  1343. '<select name="%1$s" %2$s>%3$s</select>',  
  1344. '_gaddon_setting_' . $name, implode( ' ', $attributes ), $this->get_select_options( $field['choices'], $value ) 
  1345. ); 
  1346.  
  1347. if ( $this->field_failed_validation( $field ) ) { 
  1348. $html .= $this->get_error_icon( $field ); 
  1349.  
  1350. if ( $echo ) { 
  1351. echo $html; 
  1352.  
  1353. return $html; 
  1354.  
  1355. /** 
  1356. * Renders and initializes a drop down field with a input field for custom input based on the $field array. 
  1357. *  
  1358. * @param array $field - Field array containing the configuration options of this field 
  1359. * @param bool $echo = true - true to echo the output to the screen, false to simply return the contents as a string 
  1360. *  
  1361. * @return string The HTML for the field 
  1362. */ 
  1363. protected function settings_select_custom( $field, $echo = true ) { 
  1364.  
  1365. /** Prepare select field */ 
  1366. $select_field = $field; 
  1367. $select_field_value = $this->get_setting( $select_field['name'], rgar( $select_field, 'default_value' ) ); 
  1368. $select_field['onchange'] = ''; 
  1369. $select_field['class'] = ( isset( $select_field['class'] ) ) ? $select_field['class'] . 'gaddon-setting-select-custom' : 'gaddon-setting-select-custom'; 
  1370.  
  1371. /** Prepare input field */ 
  1372. $input_field = $field; 
  1373. $input_field['name'] .= '_custom'; 
  1374. $input_field['style'] = 'width:200px;max-width:90%;'; 
  1375. $input_field_display = ''; 
  1376.  
  1377. /** Loop through select choices and make sure option for custom exists */ 
  1378. $has_gf_custom = false; 
  1379. foreach ( $select_field['choices'] as $choice ) { 
  1380. if ( rgar( $choice, 'name' ) == 'gf_custom' || rgar( $choice, 'value' ) == 'gf_custom' ) { 
  1381. $has_gf_custom = true; 
  1382. if ( ! $has_gf_custom ) { 
  1383. $select_field['choices'][] = array( 
  1384. 'label' => esc_html__( 'Add Custom', 'gravityforms' ) .' ' . $select_field['label'],  
  1385. 'value' => 'gf_custom' 
  1386. ); 
  1387.  
  1388. /** If select value is "gf_custom", hide the select field and display the input field. */ 
  1389. if ( $select_field_value == 'gf_custom' || ( count( $select_field['choices'] ) == 1 && $select_field['choices'][0]['value'] == 'gf_custom' ) ) { 
  1390. $select_field['style'] = 'display:none;'; 
  1391. } else { 
  1392. $input_field_display = ' style="display:none;"'; 
  1393.  
  1394. /** Add select field */ 
  1395. $html = $this->settings_select( $select_field, false ); 
  1396.  
  1397. /** Add input field */ 
  1398. $html .= '<div class="gaddon-setting-select-custom-container"'. $input_field_display .'>'; 
  1399. $html .= count( $select_field['choices'] ) > 1 ? '<a href="#" class="select-custom-reset">Reset</a>' : ''; 
  1400. $html .= $this->settings_text( $input_field, false ); 
  1401. $html .= '</div>'; 
  1402.  
  1403. if ( $echo ) { 
  1404. echo $html; 
  1405.  
  1406. return $html; 
  1407.  
  1408.  
  1409. /** 
  1410. * Prepares an HTML string of options for a drop down field. 
  1411. *  
  1412. * @param array $choices - Array containing all the options for the drop down field 
  1413. * @param string $selected_value - The value currently selected for the field 
  1414. *  
  1415. * @return string The HTML for the select options 
  1416. */ 
  1417. public function get_select_options( $choices, $selected_value ) { 
  1418.  
  1419. $options = ''; 
  1420.  
  1421. foreach ( $choices as $choice ) { 
  1422.  
  1423. if ( isset( $choice['choices'] ) ) { 
  1424.  
  1425. $options .= sprintf( '<optgroup label="%1$s">%2$s</optgroup>', esc_attr( $choice['label'] ), $this->get_select_options( $choice['choices'], $selected_value ) ); 
  1426.  
  1427. } else { 
  1428.  
  1429. if ( ! isset( $choice['value'] ) ) { 
  1430. $choice['value'] = $choice['label']; 
  1431.  
  1432. $options .= $this->get_select_option( $choice, $selected_value ); 
  1433.  
  1434.  
  1435. return $options; 
  1436.  
  1437. /** 
  1438. * Prepares an HTML string for a single drop down field option. 
  1439. *  
  1440. * @access protected 
  1441. * @param array $choice - Array containing the settings for the drop down option 
  1442. * @param string $selected_value - The value currently selected for the field 
  1443. *  
  1444. * @return string The HTML for the select choice 
  1445. */ 
  1446. protected function get_select_option( $choice, $selected_value ) { 
  1447. if ( is_array( $selected_value ) ) { 
  1448. $selected = in_array( $choice['value'], $selected_value ) ? "selected='selected'" : ''; 
  1449. } else { 
  1450. $selected = selected( $selected_value, $choice['value'], false ); 
  1451.  
  1452. return sprintf( '<option value="%1$s" %2$s>%3$s</option>', esc_attr( $choice['value'] ), $selected, $choice['label'] ); 
  1453.  
  1454.  
  1455. //------------- Field Map Field Type -------------------------- 
  1456.  
  1457. public function settings_field_map( $field, $echo = true ) { 
  1458.  
  1459. $html = ''; 
  1460. $field_map = rgar( $field, 'field_map' ); 
  1461.  
  1462. if ( empty( $field_map ) ) { 
  1463. return $html; 
  1464.  
  1465. $form_id = rgget( 'id' ); 
  1466.  
  1467.  
  1468. $html .= '<table class="settings-field-map-table" cellspacing="0" cellpadding="0">' . 
  1469. $this->field_map_table_header() . 
  1470. '<tbody>'; 
  1471.  
  1472. foreach ( $field['field_map'] as $child_field ) { 
  1473.  
  1474. if ( ! $this->setting_dependency_met( rgar( $child_field, 'dependency' ) ) ) { 
  1475. continue; 
  1476.  
  1477. $child_field['name'] = $this->get_mapped_field_name( $field, $child_field['name'] ); 
  1478. $required = rgar( $child_field, 'required' ) ? $this->get_required_indicator( $child_field ) : ''; 
  1479.  
  1480. $html .= ' 
  1481. <tr> 
  1482. <td> 
  1483. <label for="' . $child_field['name'] . '">' . $child_field['label'] . ' ' . $required . '<label> 
  1484. </td> 
  1485. <td>' . 
  1486. $this->settings_field_map_select( $child_field, $form_id ) . 
  1487. '</td> 
  1488. </tr>'; 
  1489.  
  1490. $html .= ' 
  1491. </tbody> 
  1492. </table>'; 
  1493.  
  1494. if ( $echo ) { 
  1495. echo $html; 
  1496.  
  1497. return $html; 
  1498.  
  1499. public function field_map_table_header() { 
  1500. return '<thead> 
  1501. <tr> 
  1502. <th>' . $this->field_map_title() . '</th> 
  1503. <th>' . esc_html__( 'Form Field', 'gravityforms' ) . '</th> 
  1504. </tr> 
  1505. </thead>'; 
  1506.  
  1507. public function settings_field_map_select( $field, $form_id ) { 
  1508.  
  1509. $field_type = rgempty( 'field_type', $field ) ? null : $field['field_type']; 
  1510. $exclude_field_types = rgempty( 'exclude_field_types', $field ) ? null : $field['exclude_field_types']; 
  1511.  
  1512. $field['choices'] = $this->get_field_map_choices( $form_id, $field_type, $exclude_field_types ); 
  1513.  
  1514. if ( empty( $field['choices'] ) || ( count( $field['choices'] ) == 1 && rgblank( $field['choices'][0]['value'] ) ) ) { 
  1515.  
  1516. if ( ( ! is_array( $field_type ) && ! rgblank( $field_type ) ) || ( is_array( $field_type ) && count( $field_type ) == 1 ) ) { 
  1517.  
  1518. $type = is_array( $field_type ) ? $field_type[0] : $field_type; 
  1519. $type = ucfirst( GF_Fields::get( $type )->get_form_editor_field_title() ); 
  1520.  
  1521. return sprintf( __( 'Please add a %s field to your form.', 'gravityforms' ), $type ); 
  1522.  
  1523.  
  1524.  
  1525. return $this->settings_select( $field, false ); 
  1526.  
  1527.  
  1528. protected function field_map_title() { 
  1529. return esc_html__( 'Field', 'gravityforms' ); 
  1530.  
  1531. public static function get_field_map_choices( $form_id, $field_type = null, $exclude_field_types = null ) { 
  1532.  
  1533. $form = RGFormsModel::get_form_meta( $form_id ); 
  1534.  
  1535. $fields = array(); 
  1536.  
  1537. // Setup first choice  
  1538. if ( rgblank( $field_type ) || ( is_array( $field_type ) && count( $field_type ) > 1 ) ) { 
  1539.  
  1540. $first_choice_label = __( 'Select a Field', 'gravityforms' ); 
  1541.  
  1542. } else { 
  1543.  
  1544. $type = is_array( $field_type ) ? $field_type[0] : $field_type; 
  1545. $type = ucfirst( GF_Fields::get( $type )->get_form_editor_field_title() ); 
  1546.  
  1547. $first_choice_label = sprintf( __( 'Select a %s Field', 'gravityforms' ), $type ); 
  1548.  
  1549.  
  1550. $fields[] = array( 'value' => '', 'label' => $first_choice_label ); 
  1551.  
  1552. // if field types not restricted add the default fields and entry meta 
  1553. if ( is_null( $field_type ) ) { 
  1554. $fields[] = array( 'value' => 'id', 'label' => esc_html__( 'Entry ID', 'gravityforms' ) ); 
  1555. $fields[] = array( 'value' => 'date_created', 'label' => esc_html__( 'Entry Date', 'gravityforms' ) ); 
  1556. $fields[] = array( 'value' => 'ip', 'label' => esc_html__( 'User IP', 'gravityforms' ) ); 
  1557. $fields[] = array( 'value' => 'source_url', 'label' => esc_html__( 'Source Url', 'gravityforms' ) ); 
  1558. $fields[] = array( 'value' => 'form_title', 'label' => esc_html__( 'Form Title', 'gravityforms' ) ); 
  1559.  
  1560. $entry_meta = GFFormsModel::get_entry_meta( $form['id'] ); 
  1561. foreach ( $entry_meta as $meta_key => $meta ) { 
  1562. $fields[] = array( 'value' => $meta_key, 'label' => rgars( $entry_meta, "{$meta_key}/label" ) ); 
  1563.  
  1564. // Populate form fields 
  1565. if ( is_array( $form['fields'] ) ) { 
  1566. foreach ( $form['fields'] as $field ) { 
  1567. $input_type = $field->get_input_type(); 
  1568. $inputs = $field->get_entry_inputs(); 
  1569. $field_is_valid_type = ( empty( $field_type ) || ( is_array( $field_type ) && in_array( $input_type, $field_type ) ) || ( ! empty( $field_type ) && $input_type == $field_type ) ); 
  1570.  
  1571. if ( is_null( $exclude_field_types ) ) { 
  1572. $exclude_field = false; 
  1573. } elseif ( is_array( $exclude_field_types ) ) { 
  1574. if ( in_array( $input_type, $exclude_field_types ) ) { 
  1575. $exclude_field = true; 
  1576. } else { 
  1577. $exclude_field = false; 
  1578. } else { 
  1579. //not array, so should be single string 
  1580. if ( $input_type == $exclude_field_types ) { 
  1581. $exclude_field = true; 
  1582. } else { 
  1583. $exclude_field = false; 
  1584.  
  1585. if ( is_array( $inputs ) && $field_is_valid_type && ! $exclude_field ) { 
  1586. //If this is an address field, add full name to the list 
  1587. if ( $input_type == 'address' ) { 
  1588. $fields[] = array( 
  1589. 'value' => $field->id,  
  1590. 'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Full', 'gravityforms' ) . ')' 
  1591. ); 
  1592. //If this is a name field, add full name to the list 
  1593. if ( $input_type == 'name' ) { 
  1594. $fields[] = array( 
  1595. 'value' => $field->id,  
  1596. 'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Full', 'gravityforms' ) . ')' 
  1597. ); 
  1598. //If this is a checkbox field, add to the list 
  1599. if ( $input_type == 'checkbox' ) { 
  1600. $fields[] = array( 
  1601. 'value' => $field->id,  
  1602. 'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Selected', 'gravityforms' ) . ')' 
  1603. ); 
  1604.  
  1605. foreach ( $inputs as $input ) { 
  1606. $fields[] = array( 
  1607. 'value' => $input['id'],  
  1608. 'label' => GFCommon::get_label( $field, $input['id'] ) 
  1609. ); 
  1610. } elseif ( $input_type == 'list' && $field->enableColumns && $field_is_valid_type && ! $exclude_field ) { 
  1611. $fields[] = array( 
  1612. 'value' => $field->id,  
  1613. 'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Full', 'gravityforms' ) . ')' 
  1614. ); 
  1615. $col_index = 0; 
  1616. foreach ( $field->choices as $column ) { 
  1617. $fields[] = array( 
  1618. 'value' => $field->id . '.' . $col_index,  
  1619. 'label' => GFCommon::get_label( $field ) . ' (' . esc_html( rgar( $column, 'text' ) ) . ')',  
  1620. ); 
  1621. $col_index ++; 
  1622. } elseif ( ! rgar( $field, 'displayOnly' ) && $field_is_valid_type && ! $exclude_field ) { 
  1623. $fields[] = array( 'value' => $field->id, 'label' => GFCommon::get_label( $field ) ); 
  1624.  
  1625. return $fields; 
  1626.  
  1627. public function get_mapped_field_name( $parent_field, $field_name ) { 
  1628. return "{$parent_field['name']}_{$field_name}"; 
  1629.  
  1630. public static function get_field_map_fields( $feed, $field_name ) { 
  1631.  
  1632. $fields = array(); 
  1633. $prefix = "{$field_name}_"; 
  1634.  
  1635. foreach ( $feed['meta'] as $name => $value ) { 
  1636. if ( strpos( $name, $prefix ) === 0 ) { 
  1637. $name = str_replace( $prefix, '', $name ); 
  1638. $fields[ $name ] = $value; 
  1639.  
  1640. return $fields; 
  1641.  
  1642. public static function get_dynamic_field_map_fields( $feed, $field_name ) { 
  1643.  
  1644. $fields = array(); 
  1645. $dynamic_fields = $feed['meta'][$field_name]; 
  1646.  
  1647. if ( ! empty( $dynamic_fields ) ) { 
  1648.  
  1649. foreach ( $dynamic_fields as $dynamic_field ) { 
  1650.  
  1651. $field_key = ( $dynamic_field['key'] == 'gf_custom' ) ? $dynamic_field['custom_key'] : $dynamic_field['key']; 
  1652. $fields[$field_key] = $dynamic_field['value']; 
  1653.  
  1654.  
  1655.  
  1656. return $fields; 
  1657.  
  1658.  
  1659. //---------------------------------------------------------------- 
  1660.  
  1661.  
  1662. public function settings_dynamic_field_map( $field, $echo = true ) { 
  1663.  
  1664. $html = ''; 
  1665. $value_field = $key_field = $custom_key_field = $field; 
  1666. $form = $this->get_current_form(); 
  1667.  
  1668. /** Setup key field drop down */ 
  1669. $key_field['choices'] = ( isset( $field['field_map'] ) ) ? $field['field_map'] : null; 
  1670. $key_field['name'] .= '_key'; 
  1671. $key_field['class'] = 'key key_{i}'; 
  1672. $key_field['style'] = 'width:200px;'; 
  1673.  
  1674. /** Setup custom key text field */ 
  1675. $custom_key_field['name'] .= '_custom_key_{i}'; 
  1676. $custom_key_field['class'] = 'custom_key custom_key_{i}'; 
  1677. $custom_key_field['style'] = 'width:200px;max-width:90%;'; 
  1678. $custom_key_field['value'] = '{custom_key}'; 
  1679.  
  1680. /** Setup value drop down */ 
  1681. $value_field['name'] .= '_custom_value'; 
  1682. $value_field['class'] = 'value value_{i}'; 
  1683.  
  1684. /** Remove unneeded values */ 
  1685. unset( $field['field_map'] ); 
  1686. unset( $value_field['field_map'] ); 
  1687. unset( $key_field['field_map'] ); 
  1688. unset( $custom_key_field['field_map'] ); 
  1689.  
  1690. //add on errors set when validation fails 
  1691. if ( $this->field_failed_validation( $field ) ) { 
  1692. $html .= $this->get_error_icon( $field ); 
  1693.  
  1694. /** Build key cell based on available field map choices */ 
  1695. if ( empty( $key_field['choices'] ) ) { 
  1696.  
  1697. /** Set key field value to "gf_custom" so custom key is used. */ 
  1698. $key_field['value'] = 'gf_custom'; 
  1699.  
  1700. /** Build HTML string */ 
  1701. $key_field_html = '<td>' . 
  1702. $this->settings_hidden( $key_field, false ) . ' 
  1703. <div class="custom-key-container"> 
  1704. ' . $this->settings_text( $custom_key_field, false ) . ' 
  1705. </div> 
  1706. </td>';  
  1707.  
  1708. } else { 
  1709.  
  1710. /** Ensure field map array has a custom key option. */ 
  1711. $has_gf_custom = false; 
  1712. foreach ( $key_field['choices'] as $choice ) { 
  1713. if ( rgar( $choice, 'name' ) == 'gf_custom' || rgar( $choice, 'value' ) == 'gf_custom' ) { 
  1714. $has_gf_custom = true; 
  1715. if ( rgar( $choice, 'choices' ) ) { 
  1716. foreach ( $choice['choices'] as $subchoice ) { 
  1717. if ( rgar( $subchoice, 'name' ) == 'gf_custom' || rgar( $subchoice, 'value' ) == 'gf_custom' ) { 
  1718. $has_gf_custom = true; 
  1719. }  
  1720. if ( ! $has_gf_custom && ! rgar( $field, 'disable_custom' ) ) { 
  1721. $key_field['choices'][] = array( 
  1722. 'label' => esc_html__( 'Add Custom Key', 'gravityforms' ),  
  1723. 'value' => 'gf_custom' 
  1724. ); 
  1725.  
  1726. /** Build HTML string */ 
  1727. $key_field_html = '<th>' . 
  1728. $this->settings_select( $key_field, false ) . ' 
  1729. <div class="custom-key-container"> 
  1730. <a href="#" class="custom-key-reset">Reset</a>' . 
  1731. $this->settings_text( $custom_key_field, false ) . ' 
  1732. </div> 
  1733. </th>'; 
  1734.  
  1735.  
  1736. $html .= ' 
  1737. <table class="settings-field-map-table" cellspacing="0" cellpadding="0"> 
  1738. <tbody class="repeater"> 
  1739. <tr> 
  1740. '. $key_field_html .' 
  1741. <td>' . 
  1742. $this->settings_field_map_select( $value_field, $form['id'] ) . ' 
  1743. </td> 
  1744. <td> 
  1745. {buttons} 
  1746. </td> 
  1747. </tr> 
  1748. </tbody> 
  1749. </table>'; 
  1750.  
  1751. $html .= $this->settings_hidden( $field, false ); 
  1752.  
  1753. $limit = empty( $field['limit'] ) ? 0 : $field['limit']; 
  1754.  
  1755. $html .= " 
  1756. <script type=\"text/javascript\"> 
  1757.  
  1758. var dynamicFieldMap". esc_attr( $field['name'] ) ." = new gfieldmap({ 
  1759.  
  1760. 'baseURL': '". GFCommon::get_base_url() ."',  
  1761. 'fieldId': '". esc_attr( $field['name'] ) ."',  
  1762. 'fieldName': '". $field['name'] ."',  
  1763. 'keyFieldName': '". $key_field['name'] ."',  
  1764. 'limit': '". $limit . "' 
  1765.  
  1766. }); 
  1767.  
  1768. </script>"; 
  1769.  
  1770. if ( $echo ) { 
  1771. echo $html; 
  1772.  
  1773. return $html; 
  1774.  
  1775.  
  1776. /** 
  1777. * Renders and initializes a drop down field based on the $field array whose choices are populated by the form's fields. 
  1778. *  
  1779. * @param array $field - Field array containing the configuration options of this field 
  1780. * @param bool $echo = true - true to echo the output to the screen, false to simply return the contents as a string 
  1781. * @return string The HTML for the field 
  1782. */ 
  1783. public function settings_field_select( $field, $echo = true ) { 
  1784.  
  1785. $args = is_array( rgar( $field, 'args' ) ) ? rgar( $field, 'args' ) : array( rgar( $field, 'args' ) ); 
  1786.  
  1787. $args = wp_parse_args( 
  1788. $args, array( 
  1789. 'append_choices' => array(),  
  1790. 'disable_first_choice' => false,  
  1791. ); 
  1792.  
  1793. $field['choices'] = array(); 
  1794.  
  1795. if ( ! $args['disable_first_choice'] ) { 
  1796.  
  1797. // Setup first choice  
  1798. if ( empty( $args['input_types'] ) || ( is_array( $args['input_types'] ) && count( $args['input_types'] ) > 1 ) ) { 
  1799.  
  1800. $first_choice_label = __( 'Select a Field', 'gravityforms' ); 
  1801.  
  1802. } else { 
  1803.  
  1804. $type = is_array( $args['input_types'] ) ? $args['input_types'][0] : $args['input_types']; 
  1805. $type = ucfirst( GF_Fields::get( $type )->get_form_editor_field_title() ); 
  1806.  
  1807. $first_choice_label = sprintf( __( 'Select a %s Field', 'gravityforms' ), $type ); 
  1808.  
  1809.  
  1810. $field['choices'][] = array( 'value' => '', 'label' => $first_choice_label ); 
  1811.  
  1812.  
  1813. $field['choices'] = array_merge( $field['choices'], $this->get_form_fields_as_choices( $this->get_current_form(), $args ) ); 
  1814.  
  1815. if ( ! empty( $args['append_choices'] ) ) { 
  1816. $field['choices'] = array_merge( $field['choices'], $args['append_choices'] ); 
  1817.  
  1818. $html = $this->settings_select( $field, false ); 
  1819.  
  1820. if ( $echo ) { 
  1821. echo $html; 
  1822.  
  1823. return $html; 
  1824.  
  1825. /** 
  1826. * Retrieve an array of form fields formatted for select, radio and checkbox settings fields. 
  1827. *  
  1828. * @access public 
  1829. * @param array $form - The form object 
  1830. * @param array $args - Additional settings to check for (field and input types to include, callback for applicable input type) 
  1831. * @return array The array of formatted form fields 
  1832. */ 
  1833. public function get_form_fields_as_choices( $form, $args = array() ) { 
  1834.  
  1835. $fields = array(); 
  1836.  
  1837. if ( ! is_array( $form['fields'] ) ) { 
  1838. return $fields; 
  1839.  
  1840. $args = wp_parse_args( 
  1841. $args, array( 
  1842. 'field_types' => array(),  
  1843. 'input_types' => array(),  
  1844. 'callback' => false 
  1845. ); 
  1846.  
  1847. foreach ( $form['fields'] as $field ) { 
  1848.  
  1849. $input_type = GFFormsModel::get_input_type( $field ); 
  1850. $is_applicable_input_type = empty( $args['input_types'] ) || in_array( $input_type, $args['input_types'] ); 
  1851.  
  1852. if ( is_callable( $args['callback'] ) ) { 
  1853. $is_applicable_input_type = call_user_func( $args['callback'], $is_applicable_input_type, $field, $form ); 
  1854.  
  1855. if ( ! $is_applicable_input_type ) { 
  1856. continue; 
  1857.  
  1858. if ( ! empty( $args['property'] ) && ( ! isset( $field->$args['property'] ) || $field->$args['property'] != $args['property_value'] ) ) { 
  1859. continue; 
  1860.  
  1861. $inputs = $field->get_entry_inputs(); 
  1862. if ( is_array( $inputs ) ) { 
  1863. // if this is an address field, add full name to the list 
  1864. if ( $input_type == 'address' ) { 
  1865. $fields[] = array( 
  1866. 'value' => $field->id,  
  1867. 'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Full', 'gravityforms' ) . ')' 
  1868. ); 
  1869. // if this is a name field, add full name to the list 
  1870. if ( $input_type == 'name' ) { 
  1871. $fields[] = array( 
  1872. 'value' => $field->id,  
  1873. 'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Full', 'gravityforms' ) . ')' 
  1874. ); 
  1875. // if this is a checkbox field, add to the list 
  1876. if ( $input_type == 'checkbox' ) { 
  1877. $fields[] = array( 
  1878. 'value' => $field->id,  
  1879. 'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Selected', 'gravityforms' ) . ')' 
  1880. ); 
  1881.  
  1882. foreach ( $inputs as $input ) { 
  1883. $fields[] = array( 
  1884. 'value' => $input['id'],  
  1885. 'label' => GFCommon::get_label( $field, $input['id'] ) 
  1886. ); 
  1887. } elseif ( $input_type == 'list' && $field->enableColumns ) { 
  1888. $fields[] = array( 
  1889. 'value' => $field->id,  
  1890. 'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Full', 'gravityforms' ) . ')' 
  1891. ); 
  1892. $col_index = 0; 
  1893. foreach ( $field->choices as $column ) { 
  1894. $fields[] = array( 
  1895. 'value' => $field->id . '.' . $col_index,  
  1896. 'label' => GFCommon::get_label( $field ) . ' (' . rgar( $column, 'text' ) . ')',  
  1897. ); 
  1898. $col_index ++; 
  1899. } elseif ( ! rgar( $field, 'displayOnly' ) ) { 
  1900. $fields[] = array( 'value' => $field->id, 'label' => GFCommon::get_label( $field ) ); 
  1901. } else { 
  1902. $fields[] = array( 
  1903. 'value' => $field->id,  
  1904. 'label' => GFCommon::get_label( $field ) 
  1905. ); 
  1906.  
  1907. return $fields; 
  1908.  
  1909. /** 
  1910. * Renders and initializes a checkbox field that displays a select field when checked based on the $field array. 
  1911. *  
  1912. * @access public 
  1913. * @param array $field - Field array containing the configuration options of this field 
  1914. * @param bool $echo = true - true to echo the output to the screen, false to simply return the contents as a string 
  1915. * @return string The HTML for the field 
  1916. */ 
  1917. public function settings_checkbox_and_select( $field, $echo = true ) { 
  1918.  
  1919. // prepare checkbox 
  1920.  
  1921. $checkbox_input = rgars( $field, 'checkbox' ); 
  1922.  
  1923. $checkbox_field = array( 
  1924. 'type' => 'checkbox',  
  1925. 'name' => $field['name'] . 'Enable',  
  1926. 'label' => esc_html__( 'Enable', 'gravityforms' ),  
  1927. 'horizontal' => true,  
  1928. 'value' => '1',  
  1929. 'choices' => false,  
  1930. 'tooltip' => false 
  1931. ); 
  1932.  
  1933. $checkbox_field = wp_parse_args( $checkbox_input, $checkbox_field ); 
  1934.  
  1935. // prepare select 
  1936.  
  1937. $select_input = rgars( $field, 'select' ); 
  1938. $is_enabled = $this->get_setting( $checkbox_field['name'] ); 
  1939.  
  1940. $select_field = array( 
  1941. 'name' => $field['name'] . 'Value',  
  1942. 'type' => 'select',  
  1943. 'class' => '',  
  1944. 'tooltip' => false 
  1945. ); 
  1946.  
  1947. $select_field['class'] .= ' ' . $select_field['name']; 
  1948.  
  1949. $select_field = wp_parse_args( $select_input, $select_field ); 
  1950.  
  1951. // a little more with the checkbox 
  1952. if( empty( $checkbox_field['choices'] ) ) { 
  1953. $checkbox_field['choices'] = array( 
  1954. array( 
  1955. 'name' => $checkbox_field['name'],  
  1956. 'label' => $checkbox_field['label'],  
  1957. 'onchange' => sprintf( "( function( $, elem ) { 
  1958. $( elem ).parents( 'td' ).css( 'position', 'relative' ); 
  1959. if( $( elem ).prop( 'checked' ) ) { 
  1960. $( '%1\$s' ).fadeIn(); 
  1961. } else { 
  1962. $( '%1\$s' ).fadeOut(); 
  1963. } )( jQuery, this );",  
  1964. "#{$select_field['name']}Span" ) 
  1965. ); 
  1966.  
  1967. // get markup 
  1968.  
  1969. $html = sprintf( 
  1970. '%s <span id="%s" class="%s">%s %s</span>',  
  1971. $this->settings_checkbox( $checkbox_field, false ),  
  1972. $select_field['name'] . 'Span',  
  1973. $is_enabled ? '' : 'hidden',  
  1974. $this->settings_select( $select_field, false ),  
  1975. $select_field['tooltip'] ? gform_tooltip( $select_field['tooltip'], rgar( $select_field, 'tooltip_class' ) . ' tooltip ' . $select_field['name'], true ) : '' 
  1976. ); 
  1977.  
  1978. if ( $echo ) { 
  1979. echo $html; 
  1980.  
  1981. return $html; 
  1982.  
  1983. /*** 
  1984. * Renders the save button for settings pages 
  1985. * @param array $field - Field array containing the configuration options of this field 
  1986. * @param bool $echo = true - true to echo the output to the screen, false to simply return the contents as a string 
  1987. * @return string The HTML 
  1988. */ 
  1989. protected function settings_save( $field, $echo = true ) { 
  1990.  
  1991. $field['type'] = 'submit'; 
  1992. $field['name'] = 'gform-settings-save'; 
  1993. $field['class'] = 'button-primary gfbutton'; 
  1994.  
  1995. if ( ! rgar( $field, 'value' ) ) { 
  1996. $field['value'] = esc_html__( 'Update Settings', 'gravityforms' ); 
  1997.  
  1998. $attributes = $this->get_field_attributes( $field ); 
  1999.  
  2000. $html = '<input 
  2001. type="' . esc_attr( $field['type'] ) . '" 
  2002. name="' . esc_attr( $field['name'] ) . '" 
  2003. value="' . esc_attr( $field['value'] ) . '" ' . implode( ' ', $attributes ) . ' />'; 
  2004.  
  2005. if ( $echo ) { 
  2006. echo $html; 
  2007.  
  2008. return $html; 
  2009.  
  2010. /** 
  2011. * Helper to create a simple conditional logic set of fields. It creates one row of conditional logic with Field/Operator/Value inputs. 
  2012. * @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. 
  2013. * @return string The HTML 
  2014. */ 
  2015. protected function simple_condition( $setting_name_root ) { 
  2016.  
  2017. $conditional_fields = $this->get_conditional_logic_fields(); 
  2018.  
  2019. $value_input = esc_js( '_gaddon_setting_' . esc_attr( $setting_name_root ) . '_value' ); 
  2020. $object_type = esc_js( "simple_condition_{$setting_name_root}" ); 
  2021.  
  2022. $str = $this->settings_select( array( 
  2023. 'name' => "{$setting_name_root}_field_id",  
  2024. 'type' => 'select',  
  2025. 'choices' => $conditional_fields,  
  2026. 'class' => 'optin_select',  
  2027. 'onchange' => "jQuery('#" . esc_js( $setting_name_root ) . "_container').html(GetRuleValues('{$object_type}', 0, jQuery(this).val(), '', '{$value_input}'));" 
  2028. ), false ); 
  2029.  
  2030. $str .= $this->settings_select( array( 
  2031. 'name' => "{$setting_name_root}_operator",  
  2032. 'type' => 'select',  
  2033. '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}'));",  
  2034. 'choices' => array( 
  2035. array( 
  2036. 'value' => 'is',  
  2037. 'label' => esc_html__( 'is', 'gravityforms' ),  
  2038. ),  
  2039. array( 
  2040. 'value' => 'isnot',  
  2041. 'label' => esc_html__( 'is not', 'gravityforms' ),  
  2042. ),  
  2043. array( 
  2044. 'value' => '>',  
  2045. 'label' => esc_html__( 'greater than', 'gravityforms' ),  
  2046. ),  
  2047. array( 
  2048. 'value' => '<',  
  2049. 'label' => esc_html__( 'less than', 'gravityforms' ),  
  2050. ),  
  2051. array( 
  2052. 'value' => 'contains',  
  2053. 'label' => esc_html__( 'contains', 'gravityforms' ),  
  2054. ),  
  2055. array( 
  2056. 'value' => 'starts_with',  
  2057. 'label' => esc_html__( 'starts with', 'gravityforms' ),  
  2058. ),  
  2059. array( 
  2060. 'value' => 'ends_with',  
  2061. 'label' => esc_html__( 'ends with', 'gravityforms' ),  
  2062. ),  
  2063. ),  
  2064.  
  2065. ), false ); 
  2066.  
  2067. $str .= sprintf( "<span id='%s_container'></span>", esc_attr( $setting_name_root ) ); 
  2068.  
  2069. $field_id = $this->get_setting( "{$setting_name_root}_field_id" ); 
  2070.  
  2071. $value = $this->get_setting( "{$setting_name_root}_value" ); 
  2072. $operator = $this->get_setting( "{$setting_name_root}_operator" ); 
  2073. if ( empty( $operator ) ) { 
  2074. $operator = 'is'; 
  2075.  
  2076. $field_id_attribute = ! empty( $field_id ) ? $field_id : 'jQuery("#' . esc_attr( $setting_name_root ) . '_field_id").val()'; 
  2077.  
  2078. $str .= "<script type='text/javascript'> 
  2079. var " . esc_attr( $setting_name_root ) . "_object = {'conditionalLogic':{'rules':[{'fieldId':'{$field_id}', 'operator':'{$operator}', 'value':'" . esc_attr( $value ) . "'}]}}; 
  2080.  
  2081. jQuery(document).ready( 
  2082. function() { 
  2083. gform.addFilter( 'gform_conditional_object', 'SimpleConditionObject' ); 
  2084.  
  2085. jQuery('#" . esc_attr( $setting_name_root ) . "_container').html( 
  2086. GetRuleValues('{$object_type}', 0, {$field_id_attribute}, '" . esc_attr( $value ) . "', '_gaddon_setting_" . esc_attr( $setting_name_root ) . "_value')); 
  2087.  
  2088. ); 
  2089. </script>"; 
  2090.  
  2091. return $str; 
  2092.  
  2093. /** 
  2094. * Parses the properties of the $field meta array and returns a set of HTML attributes to be added to the HTML element. 
  2095. * @param array $field - current field meta to be parsed. 
  2096. * @param array $default - default set of properties. Will be appended to the properties specified in the $field array 
  2097. * @return array - resulting HTML attributes ready to be included in the HTML element. 
  2098. */ 
  2099. protected function get_field_attributes( $field, $default = array() ) { 
  2100.  
  2101. /** 
  2102. * Each nonstandard property will be extracted from the $props array so it is not auto-output in the field HTML 
  2103. * @param array $field The current field meta to be parsed 
  2104. */ 
  2105. $no_output_props = apply_filters( 
  2106. 'gaddon_no_output_field_properties',  
  2107. array( 
  2108. 'default_value', 'label', 'choices', 'feedback_callback', 'checked', 'checkbox_label', 'value', 'type',  
  2109. 'validation_callback', 'required', 'hidden', 'tooltip', 'dependency', 'messages', 'name', 'args', 'exclude_field_types',  
  2110. 'field_type', 'after_input', 'input_type' 
  2111. ), $field 
  2112. ); 
  2113.  
  2114. $default_props = array( 
  2115. 'class' => '', // will default to gaddon-setting 
  2116. 'default_value' => '', // default value that should be selected or entered for the field 
  2117. ); 
  2118.  
  2119. // Property switch case 
  2120. switch ( $field['type'] ) { 
  2121. case 'select': 
  2122. $default_props['choices'] = array(); 
  2123. break; 
  2124. case 'checkbox': 
  2125. $default_props['checked'] = false; 
  2126. $default_props['checkbox_label'] = ''; 
  2127. $default_props['choices'] = array(); 
  2128. break; 
  2129. case 'text': 
  2130. default: 
  2131. break; 
  2132.  
  2133. $props = wp_parse_args( $field, $default_props ); 
  2134. $props['id'] = rgempty( 'id', $props ) ? rgar( $props, 'name' ) : rgar( $props, 'id' ); 
  2135. $props['class'] = trim( "{$props['class']} gaddon-setting gaddon-{$props['type']}" ); 
  2136.  
  2137. // extract no-output properties from $props array so they are not auto-output in the field HTML 
  2138. foreach ( $no_output_props as $prop ) { 
  2139. if ( isset( $props[ $prop ] ) ) { 
  2140. ${$prop} = $props[ $prop ]; 
  2141. unset( $props[ $prop ] ); 
  2142.  
  2143. //adding default attributes 
  2144. foreach ( $default as $key => $value ) { 
  2145. if ( isset( $props[ $key ] ) ) { 
  2146. $props[ $key ] = $value . $props[ $key ]; 
  2147. } else { 
  2148. $props[ $key ] = $value; 
  2149.  
  2150. // get an array of property strings, example: name='myFieldName' 
  2151. $prop_strings = array(); 
  2152. foreach ( $props as $prop => $value ) { 
  2153. $prop_strings[ $prop ] = "{$prop}='" . esc_attr( $value ) . "'"; 
  2154.  
  2155. return $prop_strings; 
  2156.  
  2157. /** 
  2158. * Parses the properties of the $choice meta array and returns a set of HTML attributes to be added to the HTML element. 
  2159. * @param array $choice - current choice meta to be parsed. 
  2160. * @param array $field_attributes - current field's attributes. 
  2161. * @return array - resulting HTML attributes ready to be included in the HTML element. 
  2162. */ 
  2163. protected function get_choice_attributes( $choice, $field_attributes, $default_choice_attributes = array() ) { 
  2164. $choice_attributes = $field_attributes; 
  2165. foreach ( $choice as $prop => $val ) { 
  2166. $no_output_choice_attributes = array( 
  2167. 'default_value', 'label', 'checked', 'value', 'type',  
  2168. 'validation_callback', 'required', 'tooltip',  
  2169. ); 
  2170. if ( in_array( $prop, $no_output_choice_attributes ) || is_array( $val ) ) { 
  2171. unset( $choice_attributes[ $prop ] ); 
  2172. } else { 
  2173. $choice_attributes[ $prop ] = "{$prop}='" . esc_attr( $val ) . "'"; 
  2174.  
  2175. //Adding default attributes. Either creating a new attribute or pre-pending to an existing one. 
  2176. foreach ( $default_choice_attributes as $default_attr_name => $default_attr_value ) { 
  2177.  
  2178. if ( isset( $choice_attributes[ $default_attr_name ] ) ) { 
  2179. $choice_attributes[ $default_attr_name ] = $this->prepend_attribute( $default_attr_name, $default_attr_value, $choice_attributes[ $default_attr_name ] ); 
  2180. else { 
  2181. $choice_attributes[ $default_attr_name ] = "{$default_attr_name}='" . esc_attr( $default_attr_value ) . "'"; 
  2182.  
  2183. return $choice_attributes; 
  2184.  
  2185. /*** 
  2186. * @param $name - The name of the attribute to be added 
  2187. * @param $attribute - The attribute value to be added 
  2188. * @param $current_attribute - The full string containing the current attribute value 
  2189. * @return mixed - The new attribute string with the new value added to the beginning of the list 
  2190. */ 
  2191. protected function prepend_attribute( $name, $attribute, $current_attribute ) { 
  2192. return str_replace( "{$name}='", "{$name}='{$attribute}", $current_attribute ); 
  2193.  
  2194. /** 
  2195. * Validates settings fields. 
  2196. * 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. 
  2197. * To specify a custom validation, use the 'validation_callback' field meta property and implement the validation function with the custom logic. 
  2198. * @param $fields - A list of all fields from the field meta configuration 
  2199. * @param $settings - A list of submitted settings values 
  2200. * @return bool - Returns true if all fields have passed validation, and false otherwise. 
  2201. */ 
  2202. protected function validate_settings( $fields, $settings ) { 
  2203.  
  2204. foreach ( $fields as $section ) { 
  2205.  
  2206. if ( ! $this->setting_dependency_met( rgar( $section, 'dependency' ) ) ) { 
  2207. continue; 
  2208.  
  2209. foreach ( $section['fields'] as $field ) { 
  2210.  
  2211. if ( ! $this->setting_dependency_met( rgar( $field, 'dependency' ) ) ) { 
  2212. continue; 
  2213.  
  2214. $field_setting = rgar( $settings, rgar( $field, 'name' ) ); 
  2215.  
  2216. if ( is_callable( rgar( $field, 'validation_callback' ) ) ) { 
  2217. call_user_func( rgar( $field, 'validation_callback' ), $field, $field_setting ); 
  2218. continue; 
  2219.  
  2220. switch ( $field['type'] ) { 
  2221. case 'field_map' : 
  2222.  
  2223. $this->validate_field_map_settings( $field, $settings ); 
  2224.  
  2225. break; 
  2226.  
  2227. case 'checkbox' : 
  2228.  
  2229. $this->validate_checkbox_settings( $field, $settings ); 
  2230.  
  2231. break; 
  2232.  
  2233. case 'select_custom' : 
  2234.  
  2235. $this->validate_select_custom_settings( $field, $settings ); 
  2236.  
  2237. break; 
  2238.  
  2239.  
  2240. default : 
  2241.  
  2242. if ( rgar( $field, 'required' ) && rgblank( $field_setting ) ) { 
  2243. $this->set_field_error( $field, rgar( $field, 'error_message' ) ); 
  2244.  
  2245. break; 
  2246.  
  2247. $field_errors = $this->get_field_errors(); 
  2248. $is_valid = empty( $field_errors ); 
  2249.  
  2250. return $is_valid; 
  2251.  
  2252. protected function validate_checkbox_settings( $field, $settings ) { 
  2253.  
  2254. if ( ! rgar( $field, 'required' ) ) { 
  2255. return; 
  2256.  
  2257. if ( ! is_array( rgar( $field, 'choices' ) ) ) { 
  2258. return; 
  2259.  
  2260. foreach ( $field['choices'] as $choice ) { 
  2261. $choice_setting = rgar( $settings, rgar( $choice, 'name' ) ); 
  2262. if ( ! empty( $choice_setting ) ) { 
  2263. return; 
  2264.  
  2265. $this->set_field_error( $field, rgar( $field, 'error_message' ) ); 
  2266.  
  2267. protected function validate_select_custom_settings( $field, $settings ) { 
  2268.  
  2269. if ( ! rgar( $field, 'required' ) ) { 
  2270. return; 
  2271.  
  2272. if ( ! is_array( rgar( $field, 'choices' ) ) ) { 
  2273. return; 
  2274.  
  2275. $select_value = rgar( $settings, $field['name'] ); 
  2276. $custom_value = rgar( $settings, $field['name'] . '_custom' ); 
  2277.  
  2278. if ( rgar( $field, 'required' ) && rgblank( $select_value ) ) { 
  2279. $this->set_field_error( $field ); 
  2280. } else if ( rgar( $field, 'required' ) && $select_value == 'gf_custom' && rgblank( $custom_value ) ) { 
  2281. $custom_field = $field; 
  2282. $custom_field['name'] .= '_custom'; 
  2283. $this->set_field_error( $custom_field ); 
  2284.  
  2285.  
  2286. protected function validate_field_map_settings( $field, $settings ) { 
  2287.  
  2288. $field_map = rgar( $field, 'field_map' ); 
  2289.  
  2290. if ( empty( $field_map ) ) { 
  2291. return; 
  2292.  
  2293. foreach ( $field_map as $child_field ) { 
  2294.  
  2295. if ( ! $this->setting_dependency_met( rgar( $child_field, 'dependency' ) ) ) { 
  2296. continue; 
  2297.  
  2298. $child_field['name'] = $this->get_mapped_field_name( $field, $child_field['name'] ); 
  2299. $setting_value = rgar( $settings, $child_field['name'] ); 
  2300.  
  2301. if ( rgar( $child_field, 'required' ) && rgblank( $setting_value ) ) { 
  2302. $this->set_field_error( $child_field ); 
  2303. } elseif ( rgar( $child_field, 'validation_callback' ) && is_callable( rgar( $child_field, 'validation_callback' ) ) ) { 
  2304. call_user_func( rgar( $child_field, 'validation_callback' ), $child_field, $field ); 
  2305.  
  2306.  
  2307. /** 
  2308. * Sets the validation error message 
  2309. * Sets the error message to be displayed when a field fails validation. 
  2310. * When implementing a custom validation callback function, use this function to specify the error message to be displayed. 
  2311. * @param array $field - The current field meta 
  2312. * @param string $error_message - The error message to be displayed 
  2313. */ 
  2314. protected function set_field_error( $field, $error_message = '' ) { 
  2315.  
  2316. // set default error message if none passed 
  2317. if ( ! $error_message ) { 
  2318. $error_message = esc_html__( 'This field is required.', 'gravityforms' ); 
  2319.  
  2320. $this->_setting_field_errors[ $field['name'] ] = $error_message; 
  2321.  
  2322. /** 
  2323. * Gets the validation errors for a field. 
  2324. * Returns validation errors associated with the specified field or a list of all validation messages (if a field isn't specified) 
  2325. * @param array|boolean $field - Optional. The field meta. When specified, errors for this field will be returned 
  2326. * @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 
  2327. */ 
  2328. protected function get_field_errors( $field = false ) { 
  2329.  
  2330. if ( ! $field ) { 
  2331. return $this->_setting_field_errors; 
  2332.  
  2333. return isset( $this->_setting_field_errors[ $field['name'] ] ) ? $this->_setting_field_errors[ $field['name'] ] : array(); 
  2334.  
  2335. /** 
  2336. * Gets the invalid field icon 
  2337. * Returns the markup for an alert icon to indicate and highlight invalid fields. 
  2338. * @param array $field - The field meta. 
  2339. * @return string - The full markup for the icon 
  2340. */ 
  2341. protected function get_error_icon( $field ) { 
  2342.  
  2343. $error = $this->get_field_errors( $field ); 
  2344.  
  2345. return '<span 
  2346. class="gf_tooltip tooltip" 
  2347. title="<h6>' . esc_html__( 'Validation Error', 'gravityforms' ) . '</h6>' . $error . '" 
  2348. style="display:inline-block;position:relative;right:-3px;top:1px;font-size:14px;"> 
  2349. <i class="fa fa-exclamation-circle icon-exclamation-sign gf_invalid"></i> 
  2350. </span>'; 
  2351.  
  2352. /** 
  2353. * Gets the required indicator 
  2354. * Gets the markup of the required indicator symbol to highlight fields that are required 
  2355. * @param $field - The field meta. 
  2356. * @return string - Returns markup of the required indicator symbol 
  2357. */ 
  2358. protected function get_required_indicator( $field ) { 
  2359. return '<span class="required">*</span>'; 
  2360.  
  2361. /** 
  2362. * Checks if the specified field failed validation 
  2363. * @param $field - The field meta to be checked 
  2364. * @return bool|mixed - Returns a validation error string if the field has failed validation. Otherwise returns false 
  2365. */ 
  2366. protected function field_failed_validation( $field ) { 
  2367. $field_error = $this->get_field_errors( $field ); 
  2368.  
  2369. return ! empty( $field_error ) ? $field_error : false; 
  2370.  
  2371. /** 
  2372. * Filter settings fields. 
  2373. * Runs through each field and applies the 'save_callback', if set, before saving the settings. 
  2374. * To specify a custom save filter, use the 'save_callback' field meta property and implement the save filter function with the custom logic. 
  2375. * @param $fields - A list of all fields from the field meta configuration 
  2376. * @param $settings - A list of submitted settings values 
  2377. * @return $settings - The updated settings values. 
  2378. */ 
  2379. public function filter_settings( $fields, $settings ) { 
  2380.  
  2381. foreach ( $fields as $section ) { 
  2382.  
  2383. if ( ! $this->setting_dependency_met( rgar( $section, 'dependency' ) ) ) { 
  2384. continue; 
  2385.  
  2386. foreach ( $section['fields'] as $field ) { 
  2387.  
  2388. if ( ! $this->setting_dependency_met( rgar( $field, 'dependency' ) ) ) { 
  2389. continue; 
  2390.  
  2391. $field_setting = rgar( $settings, rgar( $field, 'name' ) ); 
  2392.  
  2393. if ( is_callable( rgar( $field, 'save_callback' ) ) ) { 
  2394. $settings[ $field['name'] ] = call_user_func( rgar( $field, 'save_callback' ), $field, $field_setting ); 
  2395. continue; 
  2396.  
  2397.  
  2398. return $settings; 
  2399.  
  2400. protected function add_field_before( $name, $fields, $settings ) { 
  2401. return $this->add_field( $name, $fields, $settings, 'before' ); 
  2402.  
  2403. protected function add_field_after( $name, $fields, $settings ) { 
  2404. return $this->add_field( $name, $fields, $settings, 'after' ); 
  2405.  
  2406. protected function add_field( $name, $fields, $settings, $pos ) { 
  2407.  
  2408. if ( rgar( $fields, 'name' ) ) { 
  2409. $fields = array( $fields ); 
  2410.  
  2411. $pos_mod = $pos == 'before' ? 0 : 1; 
  2412.  
  2413. foreach ( $settings as &$section ) { 
  2414. for ( $i = 0; $i < count( $section['fields'] ); $i ++ ) { 
  2415. if ( $section['fields'][ $i ]['name'] == $name ) { 
  2416. array_splice( $section['fields'], $i + $pos_mod, 0, $fields ); 
  2417. break 2; 
  2418.  
  2419. return $settings; 
  2420.  
  2421. protected function remove_field( $name, $settings ) { 
  2422.  
  2423. foreach ( $settings as &$section ) { 
  2424. for ( $i = 0; $i < count( $section['fields'] ); $i ++ ) { 
  2425. if ( $section['fields'][ $i ]['name'] == $name ) { 
  2426. array_splice( $section['fields'], $i, 1 ); 
  2427. break 2; 
  2428.  
  2429. return $settings; 
  2430.  
  2431. protected function replace_field( $name, $fields, $settings ) { 
  2432.  
  2433. if ( rgar( $fields, 'name' ) ) { 
  2434. $fields = array( $fields ); 
  2435.  
  2436. foreach ( $settings as &$section ) { 
  2437. for ( $i = 0; $i < count( $section['fields'] ); $i ++ ) { 
  2438. if ( $section['fields'][ $i ]['name'] == $name ) { 
  2439. array_splice( $section['fields'], $i, 1, $fields ); 
  2440. break 2; 
  2441.  
  2442. return $settings; 
  2443.  
  2444.  
  2445. protected function get_field( $name, $settings ) { 
  2446. foreach ( $settings as $section ) { 
  2447. for ( $i = 0; $i < count( $section['fields'] ); $i ++ ) { 
  2448. if ( $section['fields'][ $i ]['name'] == $name ) { 
  2449. return $section['fields'][ $i ]; 
  2450.  
  2451. return false; 
  2452.  
  2453. public function build_choices( $key_value_pairs ) { 
  2454.  
  2455. $choices = array(); 
  2456.  
  2457. if ( ! is_array( $key_value_pairs ) ) { 
  2458. return $choices; 
  2459.  
  2460. $first_key = key( $key_value_pairs ); 
  2461. $is_numeric = is_int( $first_key ) && $first_key === 0; 
  2462.  
  2463. foreach ( $key_value_pairs as $value => $label ) { 
  2464. if ( $is_numeric ) { 
  2465. $value = $label; 
  2466. $choices[] = array( 'value' => $value, 'label' => $label ); 
  2467.  
  2468. return $choices; 
  2469.  
  2470. //-------------- Form settings --------------------------------------------------- 
  2471.  
  2472. /** 
  2473. * Initializes form settings page 
  2474. * Hooks up the required scripts and actions for the Form Settings page 
  2475. */ 
  2476. protected function form_settings_init() { 
  2477. $view = rgget( 'view' ); 
  2478. $subview = rgget( 'subview' ); 
  2479. if ( $this->current_user_can_any( $this->_capabilities_form_settings ) ) { 
  2480. add_action( 'gform_form_settings_menu', array( $this, 'add_form_settings_menu' ), 10, 2 ); 
  2481.  
  2482. if ( rgget( 'page' ) == 'gf_edit_forms' && $view == 'settings' && $subview == $this->_slug && $this->current_user_can_any( $this->_capabilities_form_settings ) ) { 
  2483. require_once( GFCommon::get_base_path() . '/tooltips.php' ); 
  2484. add_action( 'gform_form_settings_page_' . $this->_slug, array( $this, 'form_settings_page' ) ); 
  2485.  
  2486. /** 
  2487. * Initializes plugin settings page 
  2488. * Hooks up the required scripts and actions for the Plugin Settings page 
  2489. */ 
  2490. protected function plugin_page_init() { 
  2491.  
  2492. if ( $this->current_user_can_any( $this->_capabilities_plugin_page ) ) { 
  2493. //creates the subnav left menu 
  2494. add_filter( 'gform_addon_navigation', array( $this, 'create_plugin_page_menu' ) ); 
  2495.  
  2496.  
  2497. /** 
  2498. * Creates plugin page menu item 
  2499. * Target of gform_addon_navigation filter. Creates a menu item in the left nav, linking to the plugin page 
  2500. * @param $menus - Current list of menu items 
  2501. * @return array - Returns a new list of menu items 
  2502. */ 
  2503. public function create_plugin_page_menu( $menus ) { 
  2504.  
  2505. $menus[] = array( 'name' => $this->_slug, 'label' => $this->get_short_title(), 'callback' => array( $this, 'plugin_page_container' ), 'permission' => $this->_capabilities_plugin_page ); 
  2506.  
  2507. return $menus; 
  2508.  
  2509. /** 
  2510. * Renders the form settings page. 
  2511. * Not intended to be overridden or called directly by Add-Ons. 
  2512. * Sets up the form settings page. 
  2513. * @ignore 
  2514. */ 
  2515. public function form_settings_page() { 
  2516.  
  2517. GFFormSettings::page_header( $this->_title ); 
  2518. ?> 
  2519. <div class="gform_panel gform_panel_form_settings" id="form_settings"> 
  2520.  
  2521. <?php 
  2522. $form = $this->get_current_form(); 
  2523.  
  2524. $form_id = $form['id']; 
  2525. $form = gf_apply_filters( array( 'gform_admin_pre_render', $form_id ), $form ); 
  2526.  
  2527. if ( $this->method_is_overridden( 'form_settings' ) ) { 
  2528.  
  2529. //enables plugins to override settings page by implementing a form_settings() function 
  2530. $this->form_settings( $form ); 
  2531. } else { 
  2532.  
  2533. //saves form settings if save button was pressed 
  2534. $this->maybe_save_form_settings( $form ); 
  2535.  
  2536. //reads current form settings 
  2537. $settings = $this->get_form_settings( $form ); 
  2538. $this->set_settings( $settings ); 
  2539.  
  2540. //reading addon fields 
  2541. $sections = $this->form_settings_fields( $form ); 
  2542.  
  2543. GFCommon::display_admin_message(); 
  2544.  
  2545. $page_title = $this->form_settings_page_title(); 
  2546. if ( empty( $page_title ) ) { 
  2547. $page_title = rgar( $sections[0], 'title' ); 
  2548.  
  2549. //using first section title as page title, so disable section title 
  2550. $sections[0]['title'] = false; 
  2551. $icon = $this->form_settings_icon(); 
  2552. if ( empty( $icon ) ) { 
  2553. $icon = '<i class="fa fa-cogs"></i>'; 
  2554.  
  2555. ?> 
  2556. <h3><span><?php echo $icon ?> <?php echo $page_title ?></span></h3> 
  2557. <?php 
  2558.  
  2559. //rendering settings based on fields and current settings 
  2560. $this->render_settings( $sections ); 
  2561. ?> 
  2562.  
  2563. <script type="text/javascript"> 
  2564. var form = <?php echo json_encode( $this->get_current_form() ) ?>; 
  2565. </script> 
  2566. </div> 
  2567. <?php 
  2568. GFFormSettings::page_footer(); 
  2569.  
  2570. /*** 
  2571. * Saves form settings if the submit button was pressed 
  2572. * @param array $form The form object 
  2573. * @return null|true|false True on success, false on error, null on no action 
  2574. */ 
  2575. public function maybe_save_form_settings( $form ) { 
  2576.  
  2577. if ( $this->is_save_postback() ) { 
  2578.  
  2579. check_admin_referer( $this->_slug . '_save_settings', '_' . $this->_slug . '_save_settings_nonce' ); 
  2580.  
  2581. if ( ! $this->current_user_can_any( $this->_capabilities_form_settings ) ) { 
  2582. GFCommon::add_error_message( $this->get_save_error_message( esc_html__( "You don't have sufficient permissions to update the form settings.", 'gravityforms' ) ) ); 
  2583. return false; 
  2584.  
  2585. // store a copy of the previous settings for cases where action would only happen if value has changed 
  2586. $this->set_previous_settings( $this->get_form_settings( $form ) ); 
  2587.  
  2588. $settings = $this->get_posted_settings(); 
  2589. $sections = $this->form_settings_fields( $form ); 
  2590.  
  2591. $is_valid = $this->validate_settings( $sections, $settings ); 
  2592. $result = false; 
  2593.  
  2594. if ( $is_valid ) { 
  2595. $settings = $this->filter_settings( $sections, $settings ); 
  2596. $result = $this->save_form_settings( $form, $settings ); 
  2597.  
  2598. if ( $result ) { 
  2599. GFCommon::add_message( $this->get_save_success_message( $sections ) ); 
  2600. } else { 
  2601. GFCommon::add_error_message( $this->get_save_error_message( $sections ) ); 
  2602.  
  2603. return $result; 
  2604.  
  2605.  
  2606. /*** 
  2607. * Saves form settings to form object 
  2608. * @param array $form 
  2609. * @param array $settings 
  2610. * @return true|false True on success or false on error 
  2611. */ 
  2612. public function save_form_settings( $form, $settings ) { 
  2613. $form[ $this->_slug ] = $settings; 
  2614. $result = GFFormsModel::update_form_meta( $form['id'], $form ); 
  2615.  
  2616. return ! ( false === $result ); 
  2617.  
  2618. /** 
  2619. * Checks whether the current Add-On has a form settings page. 
  2620. * @return bool 
  2621. */ 
  2622. private function has_form_settings_page() { 
  2623. return $this->method_is_overridden( 'form_settings_fields' ) || $this->method_is_overridden( 'form_settings' ); 
  2624.  
  2625. /** 
  2626. * Custom form settings page 
  2627. * Override this function to implement a complete custom form settings page. 
  2628. * Before overriding this function, consider using the form_settings_fields() and specifying your field meta. 
  2629. */ 
  2630. protected function form_settings( $form ) { 
  2631.  
  2632. /** 
  2633. * Custom form settings title 
  2634. * Override this function to display a custom title on the Form Settings Page. 
  2635. * By default, the first section in the configuration done in form_settings_fields() will be used as the page title. 
  2636. * Use this function to override that behavior and add a custom page title. 
  2637. */ 
  2638. protected function form_settings_page_title() { 
  2639. return ''; 
  2640.  
  2641. /** 
  2642. * Override this function to customize the form settings icon 
  2643. */ 
  2644. protected function form_settings_icon() { 
  2645. return ''; 
  2646.  
  2647. /** 
  2648. * Checks whether the current Add-On has a plugin page. 
  2649. * @return bool 
  2650. */ 
  2651. private function has_plugin_page() { 
  2652. return $this->method_is_overridden( 'plugin_page' ); 
  2653.  
  2654. /** 
  2655. * Override this function to create a custom plugin page 
  2656. */ 
  2657. protected function plugin_page() { 
  2658.  
  2659. /** 
  2660. * Override this function to customize the plugin page icon 
  2661. */ 
  2662. protected function plugin_page_icon() { 
  2663. return ''; 
  2664.  
  2665. /** 
  2666. * Override this function to customize the plugin page title 
  2667. */ 
  2668. protected function plugin_page_title() { 
  2669. return $this->_title; 
  2670.  
  2671. /** 
  2672. * Plugin page container 
  2673. * Target of the plugin menu left nav icon. Displays the outer plugin page markup and calls plugin_page() to render the actual page. 
  2674. * Override plugin_page() in order to provide a custom plugin page 
  2675. */ 
  2676. public function plugin_page_container() { 
  2677. ?> 
  2678. <div class="wrap"> 
  2679. <?php 
  2680. $icon = $this->plugin_page_icon(); 
  2681. if ( ! empty( $icon ) ) { 
  2682. ?> 
  2683. <img alt="<?php echo $this->get_short_title() ?>" style="margin: 15px 7px 0pt 0pt; float: left;" src="<?php echo $icon ?>" /> 
  2684. <?php 
  2685. ?> 
  2686.  
  2687. <h2 class="gf_admin_page_title"><?php echo $this->plugin_page_title() ?></h2> 
  2688. <?php 
  2689.  
  2690. $this->plugin_page(); 
  2691. ?> 
  2692. </div> 
  2693. <?php 
  2694.  
  2695. /** 
  2696. * Checks whether the current Add-On has a top level app menu. 
  2697. * @return bool 
  2698. */ 
  2699. public function has_app_menu() { 
  2700. return $this->has_app_settings() || $this->method_is_overridden( 'get_app_menu_items' ); 
  2701.  
  2702. /** 
  2703. * Creates a top level app menu. Adds the app settings page automatically if it's configured. 
  2704. * Target of the WordPress admin_menu action. 
  2705. * Not intended to be overridden or called directly by add-ons. 
  2706. */ 
  2707. public function create_app_menu() { 
  2708.  
  2709. $has_full_access = current_user_can( 'gform_full_access' ); 
  2710. $min_cap = GFCommon::current_user_can_which( $this->_capabilities_app_menu ); 
  2711. if ( empty( $min_cap ) ) { 
  2712. $min_cap = 'gform_full_access'; 
  2713.  
  2714. $menu_items = $this->get_app_menu_items(); 
  2715.  
  2716. $addon_menus = array(); 
  2717.  
  2718. /** 
  2719. * Filters through addon menus (filter by addon slugs) 
  2720. * @param array $addon_menus A modifiable array of admin addon menus 
  2721. */ 
  2722. $addon_menus = apply_filters( 'gform_addon_app_navigation_' . $this->_slug, $addon_menus ); 
  2723.  
  2724. $parent_menu = self::get_parent_menu( $menu_items, $addon_menus ); 
  2725.  
  2726. if ( empty( $parent_menu ) ) { 
  2727. return; 
  2728.  
  2729. // Add a top-level left nav 
  2730. $callback = isset( $parent_menu['callback'] ) ? $parent_menu['callback'] : array( $this, 'app_tab_page' ); 
  2731.  
  2732. global $menu; 
  2733. $number = 10; 
  2734. $menu_position = '16.' . $number; 
  2735. while ( isset( $menu[$menu_position] ) ) { 
  2736. $number += 10; 
  2737. $menu_position = '16.' . $number; 
  2738.  
  2739. /** 
  2740. * Modify the menu position of an add-on menu 
  2741. * @param int $menu_position The Menu position of the add-on menu 
  2742. */ 
  2743. $menu_position = apply_filters( 'gform_app_menu_position_' . $this->_slug, $menu_position ); 
  2744. $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 ); 
  2745.  
  2746. if ( method_exists( $this, 'load_screen_options' ) ) { 
  2747. add_action( "load-$this->app_hook_suffix", array( $this, 'load_screen_options' ) ); 
  2748.  
  2749. // Adding submenu pages 
  2750. foreach ( $menu_items as $menu_item ) { 
  2751. $callback = isset( $menu_item['callback'] ) ? $menu_item['callback'] : array( $this, 'app_tab_page' ); 
  2752. 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 ); 
  2753.  
  2754. if ( is_array( $addon_menus ) ) { 
  2755. foreach ( $addon_menus as $addon_menu ) { 
  2756. 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'] ); 
  2757.  
  2758. if ( $this->has_app_settings() ) { 
  2759. 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' ) ); 
  2760.  
  2761.  
  2762. /** 
  2763. * Returns the parent menu item 
  2764. * @param $menu_items 
  2765. * @param $addon_menus 
  2766. * @return array|bool The parent menu araray or false if none 
  2767. */ 
  2768. private function get_parent_menu( $menu_items, $addon_menus ) { 
  2769. $parent = false; 
  2770. if ( GFCommon::current_user_can_any( $this->_capabilities_app_menu ) ) { 
  2771. foreach ( $menu_items as $menu_item ) { 
  2772. if ( $this->current_user_can_any( $menu_item['permission'] ) ) { 
  2773. $parent = $menu_item; 
  2774. break; 
  2775. } elseif ( is_array( $addon_menus ) && sizeof( $addon_menus ) > 0 ) { 
  2776. foreach ( $addon_menus as $addon_menu ) { 
  2777. if ( $this->current_user_can_any( $addon_menu['permission'] ) ) { 
  2778. $parent = array( 'name' => $addon_menu['name'], 'callback' => $addon_menu['callback'] ); 
  2779. break; 
  2780. } elseif ( $this->has_app_settings() && $this->current_user_can_any( $this->_capabilities_app_settings ) ) { 
  2781. $parent = array( 'name' => $this->_slug . '_settings', 'callback' => array( $this, 'app_settings' ) ); 
  2782.  
  2783. return $parent; 
  2784.  
  2785. /** 
  2786. * Override this function to create a top level app menu. 
  2787. * e.g. 
  2788. * $menu_item['name'] = 'gravitycontacts'; 
  2789. * $menu_item['label'] = __("Contacts", 'gravitycontacts'); 
  2790. * $menu_item['permission'] = 'gravitycontacts_view_contacts'; 
  2791. * $menu_item['callback'] = array($this, 'app_menu'); 
  2792. * @return array The array of menu items 
  2793. */ 
  2794. protected function get_app_menu_items() { 
  2795. return array(); 
  2796.  
  2797. /** 
  2798. * Override this function to specify a custom icon for the top level app menu. 
  2799. * Accepts a dashicon class or a URL. 
  2800. * @return string 
  2801. */ 
  2802. protected function get_app_menu_icon() { 
  2803. return ''; 
  2804.  
  2805. /** 
  2806. * Override this function to load custom screen options. 
  2807. * e.g. 
  2808. * $screen = get_current_screen(); 
  2809. * if(!is_object($screen) || $screen->id != $this->app_hook_suffix) 
  2810. * return; 
  2811. * if($this->is_contact_list_page()) { 
  2812. * $args = array( 
  2813. * 'label' => __('Contacts per page', 'gravitycontacts'),  
  2814. * 'default' => 20,  
  2815. * 'option' => 'gcontacts_per_page' 
  2816. * ); 
  2817. * add_screen_option( 'per_page', $args ); 
  2818. */ 
  2819. public function load_screen_options() { 
  2820.  
  2821. /** 
  2822. * Handles the rendering of app menu items that implement the tabs UI. 
  2823. * Not intended to be overridden or called directly by add-ons. 
  2824. */ 
  2825. public function app_tab_page() { 
  2826. $page = rgget( 'page' ); 
  2827. $current_tab = rgget( 'view' ); 
  2828.  
  2829. if ( $page == $this->_slug . '_settings' ) { 
  2830.  
  2831. $tabs = $this->get_app_settings_tabs(); 
  2832.  
  2833. } else { 
  2834.  
  2835. $menu_items = $this->get_app_menu_items(); 
  2836.  
  2837. $current_menu_item = false; 
  2838. foreach ( $menu_items as $menu_item ) { 
  2839. if ( $menu_item['name'] == $page ) { 
  2840. $current_menu_item = $menu_item; 
  2841. break; 
  2842.  
  2843. if ( empty( $current_menu_item ) ) { 
  2844. return; 
  2845.  
  2846. if ( empty( $current_menu_item['tabs'] ) ) { 
  2847. return; 
  2848.  
  2849. $tabs = $current_menu_item['tabs']; 
  2850.  
  2851. if ( empty( $current_tab ) ) { 
  2852. foreach ( $tabs as $tab ) { 
  2853. if ( ! isset( $tab['permission'] ) || $this->current_user_can_any( $tab['permission'] ) ) { 
  2854. $current_tab = $tab['name']; 
  2855. break; 
  2856.  
  2857. if ( empty( $current_tab ) ) { 
  2858. wp_die( esc_html__( "You don't have adequate permission to view this page", 'gravityforms' ) ); 
  2859.  
  2860. foreach ( $tabs as $tab ) { 
  2861. if ( $tab['name'] == $current_tab && isset( $tab['callback'] ) && is_callable( $tab['callback'] ) ) { 
  2862. if ( isset( $tab['permission'] ) && ! $this->current_user_can_any( $tab['permission'] ) ) { 
  2863. wp_die( esc_html__( "You don't have adequate permission to view this page", 'gravityforms' ) ); 
  2864.  
  2865. $title = rgar( $tab, 'title' ); 
  2866.  
  2867. if ( empty( $title ) ) { 
  2868. $title = isset( $tab['label'] ) ? $tab['label'] : $tab['name']; 
  2869.  
  2870. $this->app_tab_page_header( $tabs, $current_tab, $title, '' ); 
  2871. call_user_func( $tab['callback'] ); 
  2872. $this->app_tab_page_footer(); 
  2873.  
  2874. return; 
  2875.  
  2876. $this->app_tab_page_header( $tabs, $current_tab, $current_tab, '' ); 
  2877. $action_hook = 'gform_addon_app_' . $page . '_' . str_replace( ' ', '_', $current_tab ); 
  2878. do_action( $action_hook ); 
  2879. $this->app_tab_page_footer(); 
  2880.  
  2881.  
  2882. /** 
  2883. * Returns the form settings for the Add-On 
  2884. * @param $form 
  2885. * @return string 
  2886. */ 
  2887. protected function get_form_settings( $form ) { 
  2888. return rgar( $form, $this->_slug ); 
  2889.  
  2890. /** 
  2891. * Add the form settings tab. 
  2892. * Override this function to add the tab conditionally. 
  2893. * @param $tabs 
  2894. * @param $form_id 
  2895. * @return array 
  2896. */ 
  2897. public function add_form_settings_menu( $tabs, $form_id ) { 
  2898.  
  2899. $tabs[] = array( 'name' => $this->_slug, 'label' => $this->get_short_title(), 'query' => array( 'fid' => null ) ); 
  2900.  
  2901. return $tabs; 
  2902.  
  2903. /** 
  2904. * Override this function to specify the settings fields to be rendered on the form settings page 
  2905. */ 
  2906. protected function form_settings_fields( $form ) { 
  2907. // should return an array of sections, each section contains a title, description and an array of fields 
  2908. return array(); 
  2909.  
  2910. //-------------- Plugin Settings --------------------------------------------------- 
  2911.  
  2912. protected function plugin_settings_init() { 
  2913. $subview = rgget( 'subview' ); 
  2914. RGForms::add_settings_page( 
  2915. array( 
  2916. 'name' => $this->_slug,  
  2917. 'tab_label' => $this->get_short_title(),  
  2918. 'title' => $this->plugin_settings_title(),  
  2919. 'handler' => array( $this, 'plugin_settings_page' ),  
  2920. ); 
  2921. if ( rgget( 'page' ) == 'gf_settings' && $subview == $this->_slug && $this->current_user_can_any( $this->_capabilities_settings_page ) ) { 
  2922. require_once( GFCommon::get_base_path() . '/tooltips.php' ); 
  2923.  
  2924. add_filter( 'plugin_action_links', array( $this, 'plugin_settings_link' ), 10, 2 ); 
  2925.  
  2926.  
  2927. public function plugin_settings_link( $links, $file ) { 
  2928. if ( $file != $this->_path ) { 
  2929. return $links; 
  2930.  
  2931. array_unshift( $links, '<a href="' . admin_url( 'admin.php' ) . '?page=gf_settings&subview=' . $this->_slug . '">' . esc_html__( 'Settings', 'gravityforms' ) . '</a>' ); 
  2932.  
  2933. return $links; 
  2934.  
  2935. /** 
  2936. * Plugin settings page 
  2937. */ 
  2938. public function plugin_settings_page() { 
  2939. $icon = $this->plugin_settings_icon(); 
  2940. if ( empty( $icon ) ) { 
  2941. $icon = '<i class="fa fa-cogs"></i>'; 
  2942. ?> 
  2943.  
  2944. <h3><span><?php echo $icon ?> <?php echo $this->plugin_settings_title() ?></span></h3> 
  2945.  
  2946. <?php if ( $this->has_deprecated_elements() ) : ?> 
  2947. <div class="push-alert-red" style="border-left: 1px solid #E6DB55; border-right: 1px solid #E6DB55;"> 
  2948. <?php esc_html_e( 'This add-on needs to be updated. Please contact the developer.', 'gravityforms' ); ?> 
  2949. </div> 
  2950. <?php endif; ?> 
  2951.  
  2952. <?php 
  2953.  
  2954. if ( $this->method_is_overridden( 'plugin_settings' ) ) { 
  2955. //enables plugins to override settings page by implementing a plugin_settings() function 
  2956. $this->plugin_settings(); 
  2957. } elseif ( $this->maybe_uninstall() ) { 
  2958. ?> 
  2959. <div class="push-alert-gold" style="border-left: 1px solid #E6DB55; border-right: 1px solid #E6DB55;"> 
  2960. <?php printf( esc_html__( '%s has been successfully uninstalled. It can be re-activated from the %splugins page%s.', 'gravityforms'), $this->_title, "<a href='plugins.php'>", '</a>' ); ?> 
  2961. </div> 
  2962. <?php 
  2963. } else { 
  2964. //saves settings page if save button was pressed 
  2965. $this->maybe_save_plugin_settings(); 
  2966.  
  2967. //reads main addon settings 
  2968. $settings = $this->get_plugin_settings(); 
  2969. $this->set_settings( $settings ); 
  2970.  
  2971. //reading addon fields 
  2972. $sections = $this->plugin_settings_fields(); 
  2973.  
  2974. GFCommon::display_admin_message(); 
  2975.  
  2976. //rendering settings based on fields and current settings 
  2977. $this->render_settings( $sections, $settings ); 
  2978.  
  2979. //renders uninstall section 
  2980. $this->render_uninstall(); 
  2981.  
  2982.  
  2983.  
  2984. public function plugin_settings_title() { 
  2985. return sprintf( esc_html__( "%s Settings", "gravityforms" ), $this->get_short_title() ); 
  2986.  
  2987. protected function plugin_settings_icon() { 
  2988. return ''; 
  2989.  
  2990. /** 
  2991. * Override this function to add a custom settings page. 
  2992. */ 
  2993. protected function plugin_settings() { 
  2994.  
  2995. /** 
  2996. * Checks whether the current Add-On has a settings page. 
  2997. * @return bool 
  2998. */ 
  2999. public function has_plugin_settings_page() { 
  3000. return $this->method_is_overridden( 'plugin_settings_fields' ) || $this->method_is_overridden( 'plugin_settings_page' ) || $this->method_is_overridden( 'plugin_settings' ); 
  3001.  
  3002. /** 
  3003. * Returns the currently saved plugin settings 
  3004. * @return mixed 
  3005. */ 
  3006. public function get_plugin_settings() { 
  3007. return get_option( 'gravityformsaddon_' . $this->_slug . '_settings' ); 
  3008.  
  3009. /** 
  3010. * Get plugin setting 
  3011. * Returns the plugin setting specified by the $setting_name parameter 
  3012. * @param string $setting_name - Plugin setting to be returned 
  3013. * @return mixed - Returns the specified plugin setting or null if the setting doesn't exist 
  3014. */ 
  3015. public function get_plugin_setting( $setting_name ) { 
  3016. $settings = $this->get_plugin_settings(); 
  3017.  
  3018. return isset( $settings[ $setting_name ] ) ? $settings[ $setting_name ] : null; 
  3019.  
  3020. /** 
  3021. * Updates plugin settings with the provided settings 
  3022. * @param array $settings - Plugin settings to be saved 
  3023. */ 
  3024. protected function update_plugin_settings( $settings ) { 
  3025. update_option( 'gravityformsaddon_' . $this->_slug . '_settings', $settings ); 
  3026.  
  3027. /** 
  3028. * Saves the plugin settings if the submit button was pressed 
  3029. */ 
  3030. protected function maybe_save_plugin_settings() { 
  3031.  
  3032. if ( $this->is_save_postback() ) { 
  3033.  
  3034. check_admin_referer( $this->_slug . '_save_settings', '_' . $this->_slug . '_save_settings_nonce' ); 
  3035.  
  3036. if ( ! $this->current_user_can_any( $this->_capabilities_settings_page ) ) { 
  3037. GFCommon::add_error_message( $this->get_save_error_message( esc_html__( "You don't have sufficient permissions to update the settings.", 'gravityforms' ) ) ); 
  3038. return false; 
  3039.  
  3040. // store a copy of the previous settings for cases where action would only happen if value has changed 
  3041. $this->set_previous_settings( $this->get_plugin_settings() ); 
  3042.  
  3043. $settings = $this->get_posted_settings(); 
  3044. $sections = $this->plugin_settings_fields(); 
  3045. $is_valid = $this->validate_settings( $sections, $settings ); 
  3046.  
  3047. if ( $is_valid ) { 
  3048. $settings = $this->filter_settings( $sections, $settings ); 
  3049. $this->update_plugin_settings( $settings ); 
  3050. GFCommon::add_message( $this->get_save_success_message( $sections ) ); 
  3051. } else { 
  3052. GFCommon::add_error_message( $this->get_save_error_message( $sections ) ); 
  3053.  
  3054.  
  3055. /** 
  3056. * Override this function to specify the settings fields to be rendered on the plugin settings page 
  3057. * @return array 
  3058. */ 
  3059. public function plugin_settings_fields() { 
  3060. // should return an array of sections, each section contains a title, description and an array of fields 
  3061. return array(); 
  3062.  
  3063. //-------------- App Settings --------------------------------------------------- 
  3064.  
  3065. /** 
  3066. * Returns the tabs for the settings app menu item 
  3067. * Not intended to be overridden or called directly by add-ons. 
  3068. * @return array|mixed|void 
  3069. */ 
  3070. public function get_app_settings_tabs() { 
  3071.  
  3072. //build left side options, always have app Settings first and Uninstall last, put add-ons in the middle 
  3073.  
  3074. $setting_tabs = array( array( 'name' => 'settings', 'label' => esc_html__( 'Settings', 'gravityforms' ), 'callback' => array( $this, 'app_settings_tab' ) ) ); 
  3075.  
  3076. $setting_tabs = apply_filters( 'gform_addon_app_settings_menu_' . $this->_slug, $setting_tabs ); 
  3077.  
  3078. if ( $this->current_user_can_any( $this->_capabilities_uninstall ) ) { 
  3079. $setting_tabs[] = array( 'name' => 'uninstall', 'label' => esc_html__( 'Uninstall', 'gravityforms' ), 'callback' => array( $this, 'app_settings_uninstall_tab' ) ); 
  3080.  
  3081. ksort( $setting_tabs, SORT_NUMERIC ); 
  3082.  
  3083. return $setting_tabs; 
  3084.  
  3085. /** 
  3086. * Renders the app settings uninstall tab. 
  3087. * Not intended to be overridden or called directly by add-ons. 
  3088. */ 
  3089. protected function app_settings_uninstall_tab() { 
  3090.  
  3091. if ( $this->maybe_uninstall() ) { 
  3092. ?> 
  3093. <div class="push-alert-gold" style="border-left: 1px solid #E6DB55; border-right: 1px solid #E6DB55;"> 
  3094. <?php printf( esc_html__( '%s has been successfully uninstalled. It can be re-activated from the %splugins page%s.', 'gravityforms' ), esc_html( $this->_title ), "<a href='plugins.php'>", '</a>' ); ?> 
  3095. </div> 
  3096. <?php 
  3097.  
  3098. } else { 
  3099. if ( $this->current_user_can_any( $this->_capabilities_uninstall ) && ( ! function_exists( 'is_multisite' ) || ! is_multisite() || is_super_admin() ) ) { 
  3100. ?> 
  3101. <form action="" method="post"> 
  3102. <?php wp_nonce_field( 'uninstall', 'gf_addon_uninstall' ) ?> 
  3103. <?php ?> 
  3104. <h3> 
  3105. <span><i class="fa fa-times"></i> <?php printf( esc_html__( 'Uninstall %s', 'gravityforms' ), $this->get_short_title() ); ?></span> 
  3106. </h3> 
  3107.  
  3108. <div class="delete-alert alert_red"> 
  3109.  
  3110. <h3> 
  3111. <i class="fa fa-exclamation-triangle gf_invalid"></i> <?php esc_html_e( 'Warning', 'gravityforms' ); ?> 
  3112. </h3> 
  3113.  
  3114. <div class="gf_delete_notice"> 
  3115. <?php echo $this->uninstall_warning_message() ?> 
  3116. </div> 
  3117.  
  3118. <?php 
  3119. $uninstall_button = '<input type="submit" name="uninstall" value="' . sprintf( esc_attr__( 'Uninstall %s', 'gravityforms' ), $this->get_short_title() ) . '" class="button" onclick="return confirm(\'' . esc_js( $this->uninstall_confirm_message() ) . '\');"/>'; 
  3120. echo $uninstall_button; 
  3121. ?> 
  3122.  
  3123. </div> 
  3124. </form> 
  3125. <?php 
  3126.  
  3127. /** 
  3128. * Renders the header for the tabs UI. 
  3129. * @param $tabs 
  3130. * @param $current_tab 
  3131. * @param $title 
  3132. * @param string $message 
  3133. */ 
  3134. protected function app_tab_page_header( $tabs, $current_tab, $title, $message = '' ) { 
  3135. $min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG || isset( $_GET['gform_debug'] ) ? '' : '.min'; 
  3136. // register admin styles 
  3137. wp_register_style( 'gform_admin', GFCommon::get_base_url() . "/css/admin{$min}.css" ); 
  3138. wp_print_styles( array( 'jquery-ui-styles', 'gform_admin' ) ); 
  3139.  
  3140. ?> 
  3141.  
  3142. <div class="wrap <?php echo GFCommon::get_browser_class() ?>"> 
  3143.  
  3144. <?php if ( $message ) { ?> 
  3145. <div id="message" class="updated"><p><?php echo $message; ?></p></div> 
  3146. <?php } ?> 
  3147.  
  3148. <h2><?php echo esc_html( $title ) ?></h2> 
  3149.  
  3150. <div id="gform_tab_group" class="gform_tab_group vertical_tabs"> 
  3151. <ul id="gform_tabs" class="gform_tabs"> 
  3152. <?php 
  3153. foreach ( $tabs as $tab ) { 
  3154. if ( isset( $tab['permission'] ) && ! $this->current_user_can_any( $tab['permission'] ) ) { 
  3155. continue; 
  3156. $label = isset( $tab['label'] ) ? $tab['label'] : $tab['name']; 
  3157. ?> 
  3158. <li <?php echo urlencode( $current_tab ) == $tab['name'] ? "class='active'" : '' ?>> 
  3159. <a href="<?php echo esc_url( add_query_arg( array( 'view' => $tab['name'] ) ) ); ?>"><?php echo esc_html( $label ) ?></a> 
  3160. </li> 
  3161. <?php 
  3162. ?> 
  3163. </ul> 
  3164.  
  3165. <div id="gform_tab_container" class="gform_tab_container"> 
  3166. <div class="gform_tab_content" id="tab_<?php echo $current_tab ?>"> 
  3167.  
  3168. <?php 
  3169.  
  3170. /** 
  3171. * Renders the footer for the tabs UI. 
  3172. */ 
  3173. protected function app_tab_page_footer() { 
  3174. ?> 
  3175. </div> <!-- / gform_tab_content --> 
  3176. </div> <!-- / gform_tab_container --> 
  3177. </div> <!-- / gform_tab_group --> 
  3178.  
  3179. <br class="clear" style="clear: both;" /> 
  3180.  
  3181. </div> <!-- / wrap --> 
  3182.  
  3183. <script type="text/javascript"> 
  3184. // JS fix for keep content contained on tabs with less content 
  3185. jQuery(document).ready(function ($) { 
  3186. $('#gform_tab_container').css('minHeight', jQuery('#gform_tabs').height() + 100); 
  3187. }); 
  3188. </script> 
  3189.  
  3190. <?php 
  3191.  
  3192. public function app_settings_tab() { 
  3193.  
  3194. require_once( GFCommon::get_base_path() . '/tooltips.php' ); 
  3195.  
  3196. $icon = $this->app_settings_icon(); 
  3197. if ( empty( $icon ) ) { 
  3198. $icon = '<i class="fa fa-cogs"></i>'; 
  3199. ?> 
  3200.  
  3201. <h3><span><?php echo $icon ?> <?php echo $this->app_settings_title() ?></span></h3> 
  3202.  
  3203. <?php 
  3204.  
  3205. if ( $this->method_is_overridden( 'app_settings' ) ) { 
  3206. //enables plugins to override settings page by implementing a plugin_settings() function 
  3207. $this->app_settings(); 
  3208. } elseif ( $this->maybe_uninstall() ) { 
  3209. ?> 
  3210. <div class="push-alert-gold" style="border-left: 1px solid #E6DB55; border-right: 1px solid #E6DB55;"> 
  3211. <?php printf( esc_html__( '%s has been successfully uninstalled. It can be re-activated from the %splugins page%s.', 'gravityforms' ), esc_html( $this->_title ), "<a href='plugins.php'>", '</a>' ); ?> 
  3212. </div> 
  3213. <?php 
  3214. } else { 
  3215. //saves settings page if save button was pressed 
  3216. $this->maybe_save_app_settings(); 
  3217.  
  3218. //reads main addon settings 
  3219. $settings = $this->get_app_settings(); 
  3220. $this->set_settings( $settings ); 
  3221.  
  3222. //reading addon fields 
  3223. $sections = $this->app_settings_fields(); 
  3224.  
  3225. GFCommon::display_admin_message(); 
  3226.  
  3227. //rendering settings based on fields and current settings 
  3228. $this->render_settings( $sections, $settings ); 
  3229.  
  3230.  
  3231.  
  3232. /** 
  3233. * Override this function to specific a custom app settings title 
  3234. * @return string 
  3235. */ 
  3236. protected function app_settings_title() { 
  3237. return sprintf( esc_html__( '%s Settings', 'gravityforms' ), $this->get_short_title() ); 
  3238.  
  3239. /** 
  3240. * Override this function to specific a custom app settings icon 
  3241. * @return string 
  3242. */ 
  3243. protected function app_settings_icon() { 
  3244. return ''; 
  3245.  
  3246. /** 
  3247. * Checks whether the current Add-On has a settings page. 
  3248. * @return bool 
  3249. */ 
  3250. public function has_app_settings() { 
  3251. return $this->method_is_overridden( 'app_settings_fields' ) || $this->method_is_overridden( 'app_settings' ); 
  3252.  
  3253. /** 
  3254. * Override this function to add a custom app settings page. 
  3255. */ 
  3256. protected function app_settings() { 
  3257.  
  3258. /** 
  3259. * Returns the currently saved plugin settings 
  3260. * @return mixed 
  3261. */ 
  3262. protected function get_app_settings() { 
  3263. return get_option( 'gravityformsaddon_' . $this->_slug . '_app_settings' ); 
  3264.  
  3265. /** 
  3266. * Get app setting 
  3267. * Returns the app setting specified by the $setting_name parameter 
  3268. * @param string $setting_name - Plugin setting to be returned 
  3269. * @return mixed - Returns the specified plugin setting or null if the setting doesn't exist 
  3270. */ 
  3271. protected function get_app_setting( $setting_name ) { 
  3272. $settings = $this->get_app_settings(); 
  3273.  
  3274. return isset( $settings[ $setting_name ] ) ? $settings[ $setting_name ] : null; 
  3275.  
  3276. /** 
  3277. * Updates app settings with the provided settings 
  3278. * @param array $settings - App settings to be saved 
  3279. */ 
  3280. protected function update_app_settings( $settings ) { 
  3281. update_option( 'gravityformsaddon_' . $this->_slug . '_app_settings', $settings ); 
  3282.  
  3283. /** 
  3284. * Saves the plugin settings if the submit button was pressed 
  3285. */ 
  3286. protected function maybe_save_app_settings() { 
  3287.  
  3288. if ( $this->is_save_postback() ) { 
  3289.  
  3290. check_admin_referer( $this->_slug . '_save_settings', '_' . $this->_slug . '_save_settings_nonce' ); 
  3291.  
  3292. if ( ! $this->current_user_can_any( $this->_capabilities_app_settings ) ) { 
  3293. GFCommon::add_error_message( $this->get_save_error_message( esc_html__( "You don't have sufficient permissions to update the settings.", 'gravityforms' ) ) ); 
  3294. return false; 
  3295.  
  3296. // store a copy of the previous settings for cases where action would only happen if value has changed 
  3297. $this->set_previous_settings( $this->get_app_settings() ); 
  3298.  
  3299. $settings = $this->get_posted_settings(); 
  3300. $sections = $this->app_settings_fields(); 
  3301. $is_valid = $this->validate_settings( $sections, $settings ); 
  3302.  
  3303. if ( $is_valid ) { 
  3304. $settings = $this->filter_settings( $sections, $settings ); 
  3305. $this->update_app_settings( $settings ); 
  3306. GFCommon::add_message( $this->get_save_success_message( $sections ) ); 
  3307. } else { 
  3308. GFCommon::add_error_message( $this->get_save_error_message( $sections ) ); 
  3309.  
  3310.  
  3311. /** 
  3312. * Override this function to specify the settings fields to be rendered on the plugin settings page 
  3313. * @return array 
  3314. */ 
  3315. public function app_settings_fields() { 
  3316. // should return an array of sections, each section contains a title, description and an array of fields 
  3317. return array(); 
  3318.  
  3319. /** 
  3320. * Returns an flattened array of field settings for the specified settings type ignoring sections. 
  3321. * @param string $settings_type The settings type. e.g. 'plugin' 
  3322. * @return array 
  3323. */ 
  3324. protected function settings_fields_only( $settings_type = 'plugin' ) { 
  3325.  
  3326. $fields = array(); 
  3327.  
  3328. if ( ! is_callable( array( $this, "{$settings_type}_settings_fields" ) ) ) { 
  3329. return $fields; 
  3330.  
  3331. $sections = call_user_func( array( $this, "{$settings_type}_settings_fields" ) ); 
  3332.  
  3333. foreach ( $sections as $section ) { 
  3334. foreach ( $section['fields'] as $field ) { 
  3335. $fields[] = $field; 
  3336.  
  3337. return $fields; 
  3338.  
  3339. //-------------- Uninstall --------------- 
  3340.  
  3341. /** 
  3342. * Override this function to customize the markup for the uninstall section on the plugin settings page 
  3343. */ 
  3344. public function render_uninstall() { 
  3345.  
  3346. ?> 
  3347. <form action="" method="post"> 
  3348. <?php wp_nonce_field( 'uninstall', 'gf_addon_uninstall' ) ?> 
  3349. <?php if ( $this->current_user_can_any( $this->_capabilities_uninstall ) ) { ?> 
  3350.  
  3351. <div class="hr-divider"></div> 
  3352.  
  3353. <h3><span><i class="fa fa-times"></i> <?php printf( esc_html__( 'Uninstall %s Add-On', 'gravityforms' ), $this->get_short_title() ) ?></span></h3> 
  3354. <div class="delete-alert alert_red"> 
  3355. <h3><i class="fa fa-exclamation-triangle gf_invalid"></i> Warning</h3> 
  3356. <div class="gf_delete_notice"> 
  3357. <?php echo $this->uninstall_warning_message() ?> 
  3358. </div> 
  3359. <input type="submit" name="uninstall" value="<?php esc_attr_e( 'Uninstall Add-On', 'gravityforms' ) ?>" class="button" onclick="return confirm('<?php echo esc_js( $this->uninstall_confirm_message() ); ?>');"> 
  3360. </div> 
  3361.  
  3362. <?php 
  3363. ?> 
  3364. </form> 
  3365. <?php 
  3366.  
  3367. protected function uninstall_warning_message() { 
  3368. return sprintf( esc_html__( '%sThis operation deletes ALL %s settings%s. If you continue, you will NOT be able to retrieve these settings.', 'gravityforms' ), '<strong>', esc_html( $this->get_short_title() ), '</strong>' ); 
  3369.  
  3370. protected function uninstall_confirm_message() { 
  3371. return sprintf( __( "Warning! ALL %s settings will be deleted. This cannot be undone. 'OK' to delete, 'Cancel' to stop", 'gravityforms' ), __( $this->get_short_title() ) ); 
  3372. /** 
  3373. * Not intended to be overridden or called directly by Add-Ons. 
  3374. * @ignore 
  3375. */ 
  3376. public function maybe_uninstall() { 
  3377. if ( rgpost( 'uninstall' ) ) { 
  3378. check_admin_referer( 'uninstall', 'gf_addon_uninstall' ); 
  3379.  
  3380. return $this->uninstall_addon(); 
  3381.  
  3382. return false; 
  3383.  
  3384. /** 
  3385. * Removes all settings and deactivates the Add-On. 
  3386. * Not intended to be overridden or called directly by Add-Ons. 
  3387. * @ignore 
  3388. */ 
  3389. public function uninstall_addon() { 
  3390.  
  3391. if ( ! $this->current_user_can_any( $this->_capabilities_uninstall ) ) { 
  3392. die( esc_html__( "You don't have adequate permission to uninstall this add-on: " . $this->_title, 'gravityforms' ) ); 
  3393.  
  3394. $continue = $this->uninstall(); 
  3395. if ( false === $continue ) { 
  3396. return false; 
  3397.  
  3398. global $wpdb; 
  3399. $lead_meta_table = GFFormsModel::get_lead_meta_table_name(); 
  3400.  
  3401. $forms = GFFormsModel::get_forms(); 
  3402. $all_form_ids = array(); 
  3403.  
  3404. // remove entry meta 
  3405. foreach ( $forms as $form ) { 
  3406. $all_form_ids[] = $form->id; 
  3407. $entry_meta = $this->get_entry_meta( array(), $form->id ); 
  3408. if ( is_array( $entry_meta ) ) { 
  3409. foreach ( array_keys( $entry_meta ) as $meta_key ) { 
  3410. $sql = $wpdb->prepare( "DELETE from $lead_meta_table WHERE meta_key=%s", $meta_key ); 
  3411. $wpdb->query( $sql ); 
  3412.  
  3413. //remove form settings 
  3414. if ( ! empty( $all_form_ids ) ) { 
  3415. $form_metas = GFFormsModel::get_form_meta_by_id( $all_form_ids ); 
  3416. require_once( GFCommon::get_base_path() . '/form_detail.php' ); 
  3417. foreach ( $form_metas as $form_meta ) { 
  3418. if ( isset( $form_meta[ $this->_slug ] ) ) { 
  3419. unset( $form_meta[ $this->_slug ] ); 
  3420. $form_json = json_encode( $form_meta ); 
  3421. GFFormDetail::save_form_info( $form_meta['id'], addslashes( $form_json ) ); 
  3422.  
  3423. //removing options 
  3424. delete_option( 'gravityformsaddon_' . $this->_slug . '_settings' ); 
  3425. delete_option( 'gravityformsaddon_' . $this->_slug . '_app_settings' ); 
  3426. delete_option( 'gravityformsaddon_' . $this->_slug . '_version' ); 
  3427.  
  3428.  
  3429. //Deactivating plugin 
  3430. deactivate_plugins( $this->_path ); 
  3431. update_option( 'recently_activated', array( $this->_path => time() ) + (array) get_option( 'recently_activated' ) ); 
  3432.  
  3433. return true; 
  3434.  
  3435.  
  3436. /** 
  3437. * Called when the user chooses to uninstall the Add-On - after permissions have been checked and before removing 
  3438. * all Add-On settings and Form settings. 
  3439. * Override this method to perform additional functions such as dropping database tables. 
  3440. * Return false to cancel the uninstall request. 
  3441. */ 
  3442. protected function uninstall() { 
  3443. return true; 
  3444.  
  3445. //-------------- Enforce minimum GF version --------------------------------------------------- 
  3446.  
  3447. /** 
  3448. * Target for the after_plugin_row action hook. Checks whether the current version of Gravity Forms 
  3449. * is supported and outputs a message just below the plugin info on the plugins page. 
  3450. * Not intended to be overridden or called directly by Add-Ons. 
  3451. * @ignore 
  3452. */ 
  3453. public function plugin_row() { 
  3454. if ( ! self::is_gravityforms_supported( $this->_min_gravityforms_version ) ) { 
  3455. $message = $this->plugin_message(); 
  3456. self::display_plugin_message( $message, true ); 
  3457.  
  3458. /** 
  3459. * Returns the message that will be displayed if the current version of Gravity Forms is not supported. 
  3460. * Override this method to display a custom message. 
  3461. */ 
  3462. public function plugin_message() { 
  3463. $message = sprintf( esc_html__( 'Gravity Forms %s is required. Activate it now or %spurchase it today!%s', 'gravityforms' ), $this->_min_gravityforms_version, "<a href='http://www.gravityforms.com'>", '</a>' ); 
  3464.  
  3465. return $message; 
  3466.  
  3467. /** 
  3468. * Formats and outs a message for the plugin row. 
  3469. * Not intended to be overridden or called directly by Add-Ons. 
  3470. * @ignore 
  3471. * @param $message 
  3472. * @param bool $is_error 
  3473. */ 
  3474. public static function display_plugin_message( $message, $is_error = false ) { 
  3475. $style = $is_error ? 'style="background-color: #ffebe8;"' : ''; 
  3476. echo '</tr><tr class="plugin-update-tr"><td colspan="5" class="plugin-update"><div class="update-message" ' . $style . '>' . $message . '</div></td>'; 
  3477.  
  3478. //--------------- Logging ------------------------------------------------------------- 
  3479.  
  3480. /** 
  3481. * Writes an error message to the Gravity Forms log. Requires the Gravity Forms logging Add-On. 
  3482. * Not intended to be overridden by Add-Ons. 
  3483. * @ignore 
  3484. */ 
  3485. public function log_error( $message ) { 
  3486. if ( class_exists( 'GFLogging' ) ) { 
  3487. GFLogging::include_logger(); 
  3488. GFLogging::log_message( $this->_slug, $message, KLogger::ERROR ); 
  3489.  
  3490. /** 
  3491. * Writes an error message to the Gravity Forms log. Requires the Gravity Forms logging Add-On. 
  3492. * Not intended to be overridden by Add-Ons. 
  3493. * @ignore 
  3494. */ 
  3495. public function log_debug( $message ) { 
  3496. if ( class_exists( 'GFLogging' ) ) { 
  3497. GFLogging::include_logger(); 
  3498. GFLogging::log_message( $this->_slug, $message, KLogger::DEBUG ); 
  3499.  
  3500. //--------------- Locking ------------------------------------------------------------ 
  3501.  
  3502. /** 
  3503. * Returns the configuration for locking 
  3504. * e.g. 
  3505. * array( 
  3506. * "object_type" => 'contact',  
  3507. * "capabilities" => array("gravityforms_contacts_edit_contacts"),  
  3508. * "redirect_url" => admin_url("admin.php?page=gf_contacts"),  
  3509. * "edit_url" => admin_url(sprintf("admin.php?page=gf_contacts&id=%d", $contact_id)),  
  3510. * "strings" => $strings 
  3511. * ); 
  3512. * Override this method to implement locking 
  3513. */ 
  3514. public function get_locking_config() { 
  3515. return array(); 
  3516.  
  3517.  
  3518. /** 
  3519. * Returns TRUE if the current page is the edit page. Otherwise, returns FALSE 
  3520. * Override this method to implement locking on the edit page. 
  3521. */ 
  3522. public function is_locking_edit_page() { 
  3523. return false; 
  3524.  
  3525. /** 
  3526. * Returns TRUE if the current page is the list page. Otherwise, returns FALSE 
  3527. * Override this method to display locking info on the list page. 
  3528. */ 
  3529. public function is_locking_list_page() { 
  3530. return false; 
  3531.  
  3532. /** 
  3533. * Returns TRUE if the current page is the view page. Otherwise, returns FALSE 
  3534. * Override this method to display locking info on the view page. 
  3535. */ 
  3536. public function is_locking_view_page() { 
  3537. return false; 
  3538.  
  3539. /** 
  3540. * Returns the ID of the object to be locked. E.g. Form ID 
  3541. * Override this method to implement locking 
  3542. */ 
  3543. public function get_locking_object_id() { 
  3544. return 0; 
  3545.  
  3546. /** 
  3547. * Outputs information about the user currently editing the specified object 
  3548. * @param int $object_id The Object ID 
  3549. * @param bool $echo Whether to echo 
  3550. * @return string The markup for the lock info 
  3551. */ 
  3552. public function lock_info( $object_id, $echo = true ) { 
  3553. $gf_locking = new GFAddonLocking( $this->get_locking_config(), $this ); 
  3554. $lock_info = $gf_locking->lock_info( $object_id, false ); 
  3555. if ( $echo ) { 
  3556. echo $lock_info; 
  3557.  
  3558. return $lock_info; 
  3559.  
  3560. /** 
  3561. * Outputs class for the row for the specified Object ID on the list page. 
  3562. * @param int $object_id The object ID 
  3563. * @param bool $echo Whether to echo 
  3564. * @return string The markup for the class 
  3565. */ 
  3566. public function list_row_class( $object_id, $echo = true ) { 
  3567. $gf_locking = new GFAddonLocking( $this->get_locking_config(), $this ); 
  3568. $class = $gf_locking->list_row_class( $object_id, false ); 
  3569. if ( $echo ) { 
  3570. echo $class; 
  3571.  
  3572. return $class; 
  3573.  
  3574. /** 
  3575. * Checked whether an object is locked 
  3576. * @param int|mixed $object_id The object ID 
  3577. * @return bool 
  3578. */ 
  3579. public function is_object_locked( $object_id ) { 
  3580. $gf_locking = new GFAddonLocking( $this->get_locking_config(), $this ); 
  3581.  
  3582. return $gf_locking->is_locked( $object_id ); 
  3583.  
  3584. //------------- Field Value Retrieval ------------------------------------------------- 
  3585.  
  3586. /** 
  3587. * Returns the value of the mapped field. 
  3588. * @param string $setting_name 
  3589. * @param array $form 
  3590. * @param array $entry 
  3591. * @param mixed $settings 
  3592. * @return string 
  3593. */ 
  3594. protected function get_mapped_field_value( $setting_name, $form, $entry, $settings = false ) { 
  3595.  
  3596. $field_id = $this->get_setting( $setting_name, '', $settings ); 
  3597.  
  3598. return $this->get_field_value( $form, $entry, $field_id ); 
  3599.  
  3600. /** 
  3601. * Returns the value of the selected field. 
  3602. * @access private 
  3603. * @param array $form 
  3604. * @param array $entry 
  3605. * @param string $field_id 
  3606. * @return string field value 
  3607. */ 
  3608. public function get_field_value( $form, $entry, $field_id ) { 
  3609.  
  3610. $field_value = ''; 
  3611.  
  3612. switch ( strtolower( $field_id ) ) { 
  3613.  
  3614. case 'form_title': 
  3615. $field_value = rgar( $form, 'title' ); 
  3616. break; 
  3617.  
  3618. case 'date_created': 
  3619. $date_created = rgar( $entry, strtolower( $field_id ) ); 
  3620. if ( empty( $date_created ) ) { 
  3621. //the date created may not yet be populated if this function is called during the validation phase and the entry is not yet created 
  3622. $field_value = gmdate( 'Y-m-d H:i:s' ); 
  3623. } else { 
  3624. $field_value = $date_created; 
  3625. break; 
  3626.  
  3627. case 'ip': 
  3628. case 'source_url': 
  3629. case 'id': 
  3630. $field_value = rgar( $entry, strtolower( $field_id ) ); 
  3631. break; 
  3632.  
  3633. default: 
  3634. $field = GFFormsModel::get_field( $form, $field_id ); 
  3635.  
  3636. if ( is_object( $field ) ) { 
  3637. $is_integer = $field_id == intval( $field_id ); 
  3638. $input_type = $field->get_input_type(); 
  3639.  
  3640. if ( $is_integer && $input_type == 'address' ) { 
  3641.  
  3642. $field_value = $this->get_full_address( $entry, $field_id ); 
  3643.  
  3644. } elseif ( $is_integer && $input_type == 'name' ) { 
  3645.  
  3646. $field_value = $this->get_full_name( $entry, $field_id ); 
  3647.  
  3648. } elseif ( $input_type == 'list' ) { 
  3649.  
  3650. $field_value = $this->get_list_field_value( $entry, $field_id, $field ); 
  3651.  
  3652. } else { 
  3653.  
  3654. $field_value = $field->get_value_export( $entry, $field_id ); 
  3655.  
  3656. } else { 
  3657.  
  3658. $field_value = rgar( $entry, $field_id ); 
  3659.  
  3660.  
  3661.  
  3662. return $this->maybe_override_field_value( $field_value, $form, $entry, $field_id ); 
  3663.  
  3664. /** 
  3665. * 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. 
  3666. * @param string $field_value 
  3667. * @param array $form 
  3668. * @param array $entry 
  3669. * @param string $field_id 
  3670. * @return string 
  3671. */ 
  3672. public function maybe_override_field_value( $field_value, $form, $entry, $field_id ) { 
  3673. /** Get Add-On slug */ 
  3674. $slug = str_replace( 'gravityforms', '', $this->_slug ); 
  3675.  
  3676. return gf_apply_filters( array( 
  3677. "gform_{$slug}_field_value",  
  3678. $form['id'],  
  3679. $field_id 
  3680. ), $field_value, $form, $entry, $field_id ); 
  3681.  
  3682. /** 
  3683. * Returns the combined value of the specified Address field. 
  3684. * @param array $entry 
  3685. * @param string $field_id 
  3686. * @return string 
  3687. */ 
  3688. protected function get_full_address( $entry, $field_id ) { 
  3689.  
  3690. return GF_Fields::get( 'address' )->get_value_export( $entry, $field_id ); 
  3691.  
  3692. /** 
  3693. * Returns the combined value of the specified Name field. 
  3694. * @param array $entry 
  3695. * @param string $field_id 
  3696. * @return string 
  3697. */ 
  3698. protected function get_full_name( $entry, $field_id ) { 
  3699.  
  3700. return GF_Fields::get( 'name' )->get_value_export( $entry, $field_id ); 
  3701.  
  3702. /** 
  3703. * Returns the value of the specified List field. 
  3704. * @param array $entry 
  3705. * @param string $field_id 
  3706. * @param object $field 
  3707. * @return string 
  3708. */ 
  3709. protected function get_list_field_value( $entry, $field_id, $field ) { 
  3710.  
  3711. return $field->get_value_export( $entry, $field_id ); 
  3712.  
  3713. /** 
  3714. * Returns the field ID of the first field of the desired type. 
  3715. *  
  3716. * @access public 
  3717. * @param string $field_type 
  3718. * @param int $subfield_id (default: null) 
  3719. * @param int $form_id (default: null) 
  3720. * @return string 
  3721. */ 
  3722. public function get_first_field_by_type( $field_type, $subfield_id = null, $form_id = null, $return_first_only = true ) { 
  3723.  
  3724. /** Get the current form ID. */ 
  3725. if ( rgblank( $form_id ) ) { 
  3726.  
  3727. $form_id = rgget( 'id' ); 
  3728.  
  3729.  
  3730. /** Get the form. */ 
  3731. $form = GFAPI::get_form( $form_id ); 
  3732.  
  3733. /** Get the request field type for the form. */ 
  3734. $fields = GFAPI::get_fields_by_type( $form, array( $field_type ) ); 
  3735.  
  3736. if ( count( $fields ) == 0 || ( count( $fields ) > 1 && $return_first_only ) ) { 
  3737.  
  3738. return null; 
  3739.  
  3740. } else { 
  3741.  
  3742. if ( rgblank( $subfield_id ) ) { 
  3743.  
  3744. return $fields[0]->id; 
  3745.  
  3746. } else { 
  3747.  
  3748. return $fields[0]->id . '.' . $subfield_id; 
  3749.  
  3750.  
  3751.  
  3752.  
  3753. //--------------- Notes ------------------ 
  3754. /** 
  3755. * Override this function to specify a custom avatar (i.e. the payment gateway logo) for entry notes created by the Add-On 
  3756. * @return string - A fully qualified URL for the avatar 
  3757. */ 
  3758. public function note_avatar() { 
  3759. return false; 
  3760.  
  3761. public function notes_avatar( $avatar, $note ) { 
  3762. if ( $note->user_name == $this->_short_title && empty( $note->user_id ) && $this->method_is_overridden( 'note_avatar', 'GFAddOn' ) ) { 
  3763. $new_avatar = $this->note_avatar(); 
  3764.  
  3765. return empty( $new_avatar ) ? $avatar : "<img alt='{$this->_short_title}' src='{$new_avatar}' class='avatar avatar-48' height='48' width='48' />"; 
  3766.  
  3767. public function add_note( $entry_id, $note, $note_type = null ) { 
  3768.  
  3769. $user_id = 0; 
  3770. $user_name = $this->_short_title; 
  3771.  
  3772. GFFormsModel::add_note( $entry_id, $user_id, $user_name, $note, $note_type ); 
  3773.  
  3774.  
  3775. //-------------- Helper functions --------------------------------------------------- 
  3776.  
  3777. protected final function method_is_overridden( $method_name, $base_class = 'GFAddOn' ) { 
  3778. $reflector = new ReflectionMethod( $this, $method_name ); 
  3779. $name = $reflector->getDeclaringClass()->getName(); 
  3780.  
  3781. return $name !== $base_class; 
  3782.  
  3783. /** 
  3784. * Returns the url of the root folder of the current Add-On. 
  3785. * @param string $full_path Optional. The full path the the plugin file. 
  3786. * @return string 
  3787. */ 
  3788. public function get_base_url( $full_path = '' ) { 
  3789. if ( empty( $full_path ) ) { 
  3790. $full_path = $this->_full_path; 
  3791.  
  3792. return plugins_url( null, $full_path ); 
  3793.  
  3794. /** 
  3795. * Returns the url of the Add-On Framework root folder. 
  3796. * @return string 
  3797. */ 
  3798. final public static function get_gfaddon_base_url() { 
  3799. return plugins_url( null, __FILE__ ); 
  3800.  
  3801. /** 
  3802. * Returns the physical path of the Add-On Framework root folder. 
  3803. * @return string 
  3804. */ 
  3805. final public static function get_gfaddon_base_path() { 
  3806. return self::_get_base_path(); 
  3807.  
  3808. /** 
  3809. * Returns the physical path of the plugins root folder. 
  3810. * @param string $full_path 
  3811. * @return string 
  3812. */ 
  3813. public function get_base_path( $full_path = '' ) { 
  3814. if ( empty( $full_path ) ) { 
  3815. $full_path = $this->_full_path; 
  3816. $folder = basename( dirname( $full_path ) ); 
  3817.  
  3818. return WP_PLUGIN_DIR . '/' . $folder; 
  3819.  
  3820. /** 
  3821. * Returns the physical path of the Add-On Framework root folder 
  3822. * @return string 
  3823. */ 
  3824. private static function _get_base_path() { 
  3825. $folder = basename( dirname( __FILE__ ) ); 
  3826.  
  3827. return GFCommon::get_base_path() . '/includes/' . $folder; 
  3828.  
  3829. /** 
  3830. * Returns the URL of the Add-On Framework root folder 
  3831. * @return string 
  3832. */ 
  3833. private static function _get_base_url() { 
  3834. $folder = basename( dirname( __FILE__ ) ); 
  3835.  
  3836. return GFCommon::get_base_url() . '/includes/' . $folder; 
  3837.  
  3838. /** 
  3839. * Checks whether the Gravity Forms is installed. 
  3840. * @return bool 
  3841. */ 
  3842. public function is_gravityforms_installed() { 
  3843. return class_exists( 'GFForms' ); 
  3844.  
  3845. public function table_exists( $table_name ) { 
  3846. global $wpdb; 
  3847.  
  3848. $count = $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" ); 
  3849.  
  3850. return ! empty( $count ); 
  3851.  
  3852. /** 
  3853. * Checks whether the current version of Gravity Forms is supported 
  3854. * @param $min_gravityforms_version 
  3855. * @return bool|mixed 
  3856. */ 
  3857. public function is_gravityforms_supported( $min_gravityforms_version = '' ) { 
  3858. if ( isset( $this->_min_gravityforms_version ) && empty( $min_gravityforms_version ) ) { 
  3859. $min_gravityforms_version = $this->_min_gravityforms_version; 
  3860.  
  3861. if ( empty( $min_gravityforms_version ) ) { 
  3862. return true; 
  3863.  
  3864. if ( class_exists( 'GFCommon' ) ) { 
  3865. $is_correct_version = version_compare( GFCommon::$version, $min_gravityforms_version, '>=' ); 
  3866.  
  3867. return $is_correct_version; 
  3868. } else { 
  3869. return false; 
  3870.  
  3871. /** 
  3872. * Returns this plugin's short title. Used to display the plugin title in small areas such as tabs 
  3873. */ 
  3874. protected function get_short_title() { 
  3875. return isset( $this->_short_title ) ? $this->_short_title : $this->_title; 
  3876.  
  3877. /** 
  3878. * Returns the unescaped URL for the plugin settings tab associated with this plugin 
  3879. */ 
  3880. protected function get_plugin_settings_url() { 
  3881. return add_query_arg( array( 'page' => 'gf_settings', 'subview' => $this->_slug ), admin_url( 'admin.php' ) ); 
  3882.  
  3883. /** 
  3884. * Returns the current form object based on the id query var. Otherwise returns false 
  3885. */ 
  3886. protected function get_current_form() { 
  3887.  
  3888. return rgempty( 'id', $_GET ) ? false : GFFormsModel::get_form_meta( rgget( 'id' ) ); 
  3889.  
  3890. /** 
  3891. * Returns TRUE if the current request is a postback, otherwise returns FALSE 
  3892. */ 
  3893. protected function is_postback() { 
  3894. return is_array( $_POST ) && count( $_POST ) > 0; 
  3895.  
  3896. /** 
  3897. * Returns TRUE if the settings "Save" button was pressed 
  3898. */ 
  3899. protected function is_save_postback() { 
  3900. return ! rgempty( 'gform-settings-save' ); 
  3901.  
  3902. /** 
  3903. * Returns TRUE if the current page is the form editor page. Otherwise, returns FALSE 
  3904. */ 
  3905. protected function is_form_editor() { 
  3906.  
  3907. if ( rgget( 'page' ) == 'gf_edit_forms' && ! rgempty( 'id', $_GET ) && rgempty( 'view', $_GET ) ) { 
  3908. return true; 
  3909.  
  3910. return false; 
  3911.  
  3912. /** 
  3913. * 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 
  3914. * @param string $tab - Specifies a specific form setting page/tab 
  3915. * @return bool 
  3916. */ 
  3917. protected function is_form_settings( $tab = null ) { 
  3918.  
  3919. $is_form_settings = rgget( 'page' ) == 'gf_edit_forms' && rgget( 'view' ) == 'settings'; 
  3920. $is_tab = $this->_tab_matches( $tab ); 
  3921.  
  3922. if ( $is_form_settings && $is_tab ) { 
  3923. return true; 
  3924. } else { 
  3925. return false; 
  3926.  
  3927. private function _tab_matches( $tabs ) { 
  3928. if ( $tabs == null ) { 
  3929. return true; 
  3930.  
  3931. if ( ! is_array( $tabs ) ) { 
  3932. $tabs = array( $tabs ); 
  3933.  
  3934. $current_tab = rgempty( 'subview', $_GET ) ? 'settings' : rgget( 'subview' ); 
  3935.  
  3936. foreach ( $tabs as $tab ) { 
  3937. if ( strtolower( $tab ) == strtolower( $current_tab ) ) { 
  3938. return true; 
  3939.  
  3940. /** 
  3941. * 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 
  3942. * @param string $tab - Specifies a specific plugin setting page/tab. 
  3943. * @return bool 
  3944. */ 
  3945. protected function is_plugin_settings( $tab = '' ) { 
  3946.  
  3947. $is_plugin_settings = rgget( 'page' ) == 'gf_settings'; 
  3948. $is_tab = $this->_tab_matches( $tab ); 
  3949.  
  3950. if ( $is_plugin_settings && $is_tab ) { 
  3951. return true; 
  3952. } else { 
  3953. return false; 
  3954.  
  3955. /** 
  3956. * 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 
  3957. * @param string $tab - Specifies a specific app setting page/tab. 
  3958. * @return bool 
  3959. */ 
  3960. protected function is_app_settings( $tab = '' ) { 
  3961.  
  3962. $is_app_settings = rgget( 'page' ) == $this->_slug . '_settings'; 
  3963. $is_tab = $this->_tab_matches( $tab ); 
  3964.  
  3965. if ( $is_app_settings && $is_tab ) { 
  3966. return true; 
  3967. } else { 
  3968. return false; 
  3969.  
  3970. /** 
  3971. * Returns TRUE if the current page is the plugin page. Otherwise returns FALSE 
  3972. * @return bool 
  3973. */ 
  3974. protected function is_plugin_page() { 
  3975.  
  3976. return strtolower( rgget( 'page' ) ) == strtolower( $this->_slug ); 
  3977.  
  3978. /** 
  3979. * Returns TRUE if the current page is the entry view page. Otherwise, returns FALSE 
  3980. * @return bool 
  3981. */ 
  3982. protected function is_entry_view() { 
  3983. if ( rgget( 'page' ) == 'gf_entries' && rgget( 'view' ) == 'entry' && ( ! isset( $_POST['screen_mode'] ) || rgpost( 'screen_mode' ) == 'view' ) ) { 
  3984. return true; 
  3985.  
  3986. return false; 
  3987.  
  3988. /** 
  3989. * Returns TRUE if the current page is the entry edit page. Otherwise, returns FALSE 
  3990. * @return bool 
  3991. */ 
  3992. protected function is_entry_edit() { 
  3993. if ( rgget( 'page' ) == 'gf_entries' && rgget( 'view' ) == 'entry' && rgpost( 'screen_mode' ) == 'edit' ) { 
  3994. return true; 
  3995.  
  3996. return false; 
  3997.  
  3998. protected function is_entry_list() { 
  3999. if ( rgget( 'page' ) == 'gf_entries' && ( rgget( 'view' ) == 'entries' || rgempty( 'view', $_GET ) ) ) { 
  4000. return true; 
  4001.  
  4002. return false; 
  4003.  
  4004. /** 
  4005. * Returns TRUE if the current page is the results page. Otherwise, returns FALSE 
  4006. */ 
  4007. protected function is_results() { 
  4008. if ( rgget( 'page' ) == 'gf_entries' && rgget( 'view' ) == 'gf_results_' . $this->_slug ) { 
  4009. return true; 
  4010.  
  4011. return false; 
  4012.  
  4013. /** 
  4014. * Returns TRUE if the current page is the print page. Otherwise, returns FALSE 
  4015. */ 
  4016. protected function is_print() { 
  4017. if ( rgget( 'gf_page' ) == 'print-entry' ) { 
  4018. return true; 
  4019.  
  4020. return false; 
  4021.  
  4022. /** 
  4023. * Returns TRUE if the current page is the preview page. Otherwise, returns FALSE 
  4024. */ 
  4025. protected function is_preview() { 
  4026. if ( rgget( 'gf_page' ) == 'preview' ) { 
  4027. return true; 
  4028.  
  4029. return false; 
  4030.  
  4031. public function has_deprecated_elements() { 
  4032. $deprecated = GFAddOn::get_all_deprecated_protected_methods( get_class( $this ) ); 
  4033. if ( ! empty( $deprecated ) ) { 
  4034. return true; 
  4035.  
  4036. return false; 
  4037.  
  4038. public static function get_all_deprecated_protected_methods($add_on_class_name = '') { 
  4039. $deprecated = array(); 
  4040. $deprecated = array_merge( $deprecated, self::get_deprecated_protected_methods_for_base_class( 'GFAddOn', $add_on_class_name )) ; 
  4041. $deprecated = array_merge( $deprecated, self::get_deprecated_protected_methods_for_base_class( 'GFFeedAddOn', $add_on_class_name ) ) ; 
  4042. $deprecated = array_merge( $deprecated, self::get_deprecated_protected_methods_for_base_class( 'GFPaymentAddOn', $add_on_class_name ) ) ; 
  4043. return $deprecated; 
  4044.  
  4045. public static function get_deprecated_protected_methods_for_base_class( $base_class_name, $add_on_class_name = '' ) { 
  4046. $deprecated = array(); 
  4047.  
  4048. if ( ! class_exists( $base_class_name ) ) { 
  4049. return $deprecated; 
  4050.  
  4051. $base_class_names = array( 
  4052. 'GFAddOn',  
  4053. 'GFFeedAddOn',  
  4054. 'GFPaymentAddOn' 
  4055. ); 
  4056.  
  4057. $base_class = new ReflectionClass( $base_class_name ); 
  4058.  
  4059. $classes = empty($add_on_class_name) ? get_declared_classes() : array( $add_on_class_name ); 
  4060.  
  4061. foreach ( $classes as $class ) { 
  4062. if ( ! is_subclass_of( $class, $base_class_name ) || in_array( $class, $base_class_names ) ) { 
  4063. continue; 
  4064.  
  4065. $add_on_class = new ReflectionClass( $class ); 
  4066. $add_on_methods = $add_on_class->getMethods( ReflectionMethod::IS_PROTECTED ); 
  4067. foreach ( $add_on_methods as $method ) { 
  4068. $method_name = $method->getName(); 
  4069. $base_has_method = $base_class->hasMethod( $method_name ); 
  4070. $is_declared_by_base_class = $base_has_method && $base_class->getMethod( $method_name )->getDeclaringClass()->getName() == $base_class_name; 
  4071. $is_overridden = $method->getDeclaringClass()->getName() == $class; 
  4072. if ( $is_declared_by_base_class && $is_overridden ) { 
  4073. $deprecated[] = $class . '::' . $method_name; 
  4074. return $deprecated; 
  4075.