iSoftwareGFHtml5Validation

Gravity Forms Html5 Validation class.

Defined (1)

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

/gravityforms-html5-validation.php  
  1. class GFHtml5Validation { 
  2.  
  3. /** 
  4. * Holds the plugin version. 
  5. * @var string 
  6. */ 
  7. protected $version = '2.4.1'; 
  8.  
  9. /** 
  10. * Holds the plugin title. 
  11. * @var string 
  12. */ 
  13. protected $title = 'Gravity Forms HTML5 Validation'; 
  14.  
  15. /** 
  16. * Holds the plugin short title. 
  17. * @var string 
  18. */ 
  19. protected $short_title = 'HTML5 Validation'; 
  20.  
  21. /** 
  22. * Holds the plugin text domain. 
  23. * @var string 
  24. */ 
  25. protected $textdomain = 'gf-html5-validation'; 
  26.  
  27. /** 
  28. * Holds the minimum WordPress version. 
  29. * @var string 
  30. */ 
  31. protected $min_wordpress_version = '3.5'; 
  32.  
  33. /** 
  34. * Holds the minimum Gravity Forms version. 
  35. * @var string 
  36. */ 
  37. protected $min_gravityforms_version = '1.9'; 
  38.  
  39. /** 
  40. * Holds a boolean flag indicating whether debugin is enabled. 
  41. * @var bool 
  42. */ 
  43. protected $debug = false; 
  44.  
  45. /** 
  46. * Holds the plugin localized strings. 
  47. * @var object 
  48. */ 
  49. protected $l10n; 
  50.  
  51. /** 
  52. * Holds a list of plugin warnings. 
  53. * @var array 
  54. */ 
  55. protected $warnings = array(); 
  56.  
  57. /** 
  58. * Class constructor which hooks the instance into the WordPress init action 
  59. */ 
  60. public function __construct( $debug = false ) { 
  61. $this->debug = $debug; 
  62. add_action( 'init', array( $this, 'init' ) ); 
  63.  
  64. /** 
  65. * Localize the plugin. 
  66. * @return void 
  67. */ 
  68. public function localize() { 
  69.  
  70. // Load plugin text domain. 
  71. load_plugin_textdomain( $this->textdomain, false, '/languages' ); 
  72.  
  73. // Setup our localized strings. 
  74. $this->l10n = (object) array( 
  75.  
  76. 'warnings' => array( 
  77.  
  78. 'wp_version' => sprintf( 
  79. esc_html__( 'Gravity Forms HTML5 Validation requires WordPress %s or greater. You must upgrade WordPress in order to use Gravity Forms HTML5 Validation', $this->textdomain ),  
  80. esc_html( $this->min_wordpress_version ) 
  81. ),  
  82.  
  83. 'gf_missing' => sprintf( 
  84. esc_html__( 'Gravity Forms HTML5 Validation is enabled but not effective. It requires %s in order to work.', $this->textdomain ),  
  85. sprintf( '<a target="_blank" href="%s">%s</a>', 'http://www.gravityforms.com/' , 'Gravity Forms' ) 
  86. ),  
  87.  
  88. 'gf_version' => sprintf( 
  89. esc_html__( 'Gravity Forms HTML5 Validation is enabled but not effective. It requires %s version <strong>%s</strong> and above in order to work.', $this->textdomain ),  
  90. sprintf( '<a target="_blank" href="%s">%s</a>', 'http://www.gravityforms.com/', 'Gravity Forms' ),  
  91. $this->min_gravityforms_version 
  92. ),  
  93.  
  94. 'gf_html5_output' => sprintf( 
  95. esc_html__( 'Gravity Forms HTML5 Validation is enabled but not effective. It requires %s setting to be enabled in %s page.', $this->textdomain ),  
  96. sprintf( '<strong>%s</strong>', esc_html__( 'Output HTML5', 'gravityforms' ) ),  
  97. sprintf( '<a href="%s">%s</a>', esc_attr( admin_url( 'admin.php?page=gf_settings' ) ), esc_html__( 'General Settings', 'gravityforms' ) ) 
  98. ),  
  99. ),  
  100.  
  101. ); 
  102.  
  103.  
  104. #region Initialization Methods 
  105.  
  106. /** 
  107. * Plugin starting point. Handles hooks and loading of language files. 
  108. * @return bool True if the plugin initialized; Otherwise false. 
  109. */ 
  110. public function init() { 
  111.  
  112. // Localize plugin. 
  113. $this->localize(); 
  114.  
  115. // We use this hook to render our warnings. 
  116. add_action( 'admin_notices', array( $this, 'render_warnings' ) ); 
  117.  
  118. // Determine whether Wordpress version is supported 
  119. if ( false === $this->is_wordpress_supported() ) { 
  120. if ( current_user_can( 'install_plugins' ) ) { 
  121. $this->add_warning( $this->l10n->warnings['wp_version'], 'plugins' ); 
  122. return false; 
  123.  
  124. // Determine whether Gravity Forms is installed. 
  125. if ( false === $this->is_gravityforms_installed() ) { 
  126. if ( current_user_can( 'install_plugins' ) ) { 
  127. $this->add_warning( $this->l10n->warnings['gf_missing'], 'plugins' ); 
  128. return false; 
  129.  
  130. // Determine whether Gravity Forms is supported. 
  131. if ( false === $this->is_gravityforms_supported() ) { 
  132. if ( current_user_can( 'install_plugins' ) ) { 
  133. $this->add_warning( $this->l10n->warnings['gf_version'], 'plugins' ); 
  134. return false; 
  135.  
  136. // We are good to go. 
  137. if ( defined( 'RG_CURRENT_PAGE' ) && RG_CURRENT_PAGE === 'admin-ajax.php' ) { 
  138. $this->init_ajax(); 
  139. } else if ( is_admin() ) { 
  140. $this->init_admin(); 
  141. } else { 
  142. $this->init_frontend(); 
  143.  
  144. return true; 
  145.  
  146. /** 
  147. * Add tasks or filters here that you want to perform both in the backend and frontend and for ajax requests. 
  148. * @return void 
  149. */ 
  150. protected function init_ajax() { 
  151. // NOOP: tbd 
  152.  
  153. /** 
  154. * Add tasks or filters here that you want to perform only in admin. 
  155. * @return void 
  156. */ 
  157. protected function init_admin() { 
  158.  
  159. // Check if we are currently on the form editor page. 
  160. if ( $this->is_form_editor() ) { 
  161.  
  162. // We use this to generate form editor warnings. 
  163. if ( false === $this->is_gravityforms_html5_enabled() ) { 
  164. $this->add_warning( $this->l10n->warnings['gf_html5_output'] ); 
  165.  
  166. /** 
  167. * Add tasks or filters here that you want to perform only in the front end. 
  168. * @return void 
  169. */ 
  170. protected function init_frontend() { 
  171.  
  172. // Enqueue frontend scripts. 
  173. add_action( 'gform_enqueue_scripts', array( $this, 'gform_enqueue_scripts' ), 10, 2 ); 
  174.  
  175. // We use this filter to manipulate the required field attributes. 
  176. add_filter( 'gform_field_content', array( $this, 'gform_field_content' ), 10, 3 ); 
  177.  
  178. // We use this filter to manipulate the next button on paginated forms. 
  179. add_filter( 'gform_next_button', array( $this, 'gform_next_button' ), 10, 2 ); 
  180.  
  181. // We use this filter to manipulate the submit button on paginated forms. 
  182. add_filter( 'gform_submit_button', array( $this, 'gform_submit_button' ), 10, 2 ); 
  183.  
  184. #endregion Initialization Methods 
  185.  
  186. #region Action/Filter Target Methods 
  187.  
  188. /** 
  189. * Target of gform_field_content both on form editor & frontend. 
  190. * @param string $field_content The current field content. 
  191. * @param array $field The current field. 
  192. * @param bool $force_frontend_label A boolean value indicating whether to force the front end label. 
  193. * @return string 
  194. */ 
  195. public function gform_field_content( $field_content, $field, $force_frontend_label ) { 
  196.  
  197. if ( ! isset( $field_content ) || ! $this->is_gravityforms_html5_enabled() || ! isset( $field ) || ! array_key_exists( 'formId', $field ) ) { 
  198. return $field_content; 
  199.  
  200. if ( false === rgar( $field, 'isRequired', false ) ) { 
  201. return $field_content; 
  202.  
  203. // Current Field Attributes. 
  204. $form_id = $field['formId']; 
  205. $field_id = $field['id']; 
  206. $field_type = rgar( $field, 'inputType', $field['type'] ); 
  207.  
  208. $field_uid = "input_{$form_id}_{$field_id}"; 
  209.  
  210. // Handle Field Content Encoding. 
  211. $encoding = mb_detect_encoding( $field_content ); 
  212. if ( 'UTF-8' !== $encoding ) { 
  213. $field_content = mb_convert_encoding( $field_content, 'UTF-8' ); } 
  214. $field_content_wrapped = "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" /></head><body>$field_content</body></html>"; 
  215.  
  216. // Disable libxml error output while we are processing html. 
  217. $use_errors = libxml_use_internal_errors( true ); 
  218.  
  219. // Prepare Dom Document and XPath. 
  220. $doc = new DomDocument(); 
  221. $doc->preserveWhiteSpace = false; // needs to be before loading, to have any effect. 
  222. $doc->formatOutput = false; 
  223. // @codingStandardsIgnoreStart 
  224. @$doc->loadHTML( $field_content_wrapped ); 
  225. // @codingStandardsIgnoreEnd 
  226. $xpath = new DOMXpath( $doc ); 
  227.  
  228. switch ( $field_type ) { 
  229.  
  230. case 'text': 
  231. case 'textarea': 
  232. case 'phone': 
  233. case 'website': 
  234. case 'number': 
  235. case 'select': 
  236. case 'multiselect': 
  237. case 'price': 
  238. case 'username': 
  239. case 'file': 
  240. case 'fileupload': 
  241. case 'post_title': 
  242. case 'post_content': 
  243. case 'post_excerpt': 
  244. case 'post_tags': 
  245. case 'post_image': 
  246. case 'post_custom': 
  247.  
  248. $field_type_map = array( 
  249. 'select' => 'select',  
  250. 'multiselect' => 'select',  
  251. 'textarea' => 'textarea',  
  252. 'post_content' => 'textarea',  
  253. 'post_excerpt' => 'textarea',  
  254. ); 
  255.  
  256. $lookup_type = array_key_exists( $field_type, $field_type_map ) ? $field_type_map[ $field_type ] : 'input' ; 
  257.  
  258. if ( $element = (( $result = $xpath->query( "//{$lookup_type}[@id='{$field_uid}']" )) ? $result->item( 0 ) : null ) ) { 
  259. $element->setAttribute( 'required', 'required' ); 
  260.  
  261. break; // End text, textarea, phone, website, number, select, multiselect, price, username, file, fileupload, post_title, post_content, post_excerpt, post_tags, post_image, post_custom field. 
  262.  
  263. case 'checkbox': 
  264.  
  265. $value = rgar( $field, 'value' ); 
  266. if ( empty( $value ) ) { 
  267. $inputs = rgar( $field, 'inputs', array() ); 
  268. foreach ( $inputs as $input ) { 
  269. $input_id = rgar( $input, 'id', false ); 
  270. if ( is_string( $input_id ) ) { 
  271. if ( $element = ( ( $result = $xpath->query( "//input[@name='input_{$input_id}']" ) ) ? $result->item( 0 ) : null ) ) { 
  272. $element->setAttribute( 'required', 'required' ); 
  273.  
  274. break; // End checkbox field; 
  275.  
  276. case 'radio': 
  277.  
  278. $choices = rgar( $field, 'choices', array() ); 
  279. for ( $i = 1; $i <= count( $choices ); $i++ ) { 
  280. if ( $element = ( ( $result = $xpath->query( "//input[@id='choice_{$form_id}_{$field_id}_{$i}']" ) ) ? $result->item( 0 ) : null ) ) { 
  281. $element->setAttribute( 'required', 'required' ); 
  282.  
  283. break; // End checkbox field; 
  284.  
  285. case 'email': 
  286.  
  287. // Process email. 
  288. if ( $element = (( $result = $xpath->query( "//input[@id='{$field_uid}']" )) ? $result->item( 0 ) : null ) ) { 
  289. $element->setAttribute( 'required', 'required' ); 
  290.  
  291. // Process email confirmation. 
  292. $email_confirm_enabled = rgar( $field, 'emailConfirmEnabled', false ); 
  293. if ( $email_confirm_enabled ) { 
  294. if ( $element = (( $result = $xpath->query( "//input[@id='{$field_uid}_2']" )) ? $result->item( 0 ) : null ) ) { 
  295. $element->setAttribute( 'required', 'required' ); 
  296.  
  297. break; // End email field. 
  298.  
  299. case 'password': 
  300.  
  301. // Process password. 
  302. if ( $element = (( $result = $xpath->query( "//input[@id='{$field_uid}']" )) ? $result->item( 0 ) : null ) ) { 
  303. $element->setAttribute( 'required', 'required' ); 
  304.  
  305. // Process password confirmation. 
  306. if ( $element = (( $result = $xpath->query( "//input[@id='{$field_uid}_2']" )) ? $result->item( 0 ) : null ) ) { 
  307. $element->setAttribute( 'required', 'required' ); 
  308.  
  309. break; // End password field. 
  310.  
  311. case 'name': 
  312.  
  313. $name_format = rgar( $field, 'nameFormat', 'normal' ); 
  314. switch ( $name_format ) { 
  315.  
  316. case 'simple': 
  317.  
  318. if ( $element = (( $result = $xpath->query( "//input[@id='{$field_uid}']" )) ? $result->item( 0 ) : null ) ) { 
  319. $element->setAttribute( 'required', 'required' ); 
  320.  
  321. break; // End simple format. 
  322.  
  323. case 'normal': 
  324. case 'extended': 
  325.  
  326. // Process name prefix. 
  327. $name_prefix_required = apply_filters( "gform_name_prefix_required_{$form_id}", apply_filters( 'gform_name_prefix_required', false, $form_id ), $form_id ); 
  328. if ( 'extended' === $name_format && $name_prefix_required ) { 
  329. if ( $element = (( $result = $xpath->query( "//input[@id='{$field_uid}_2']" )) ? $result->item( 0 ) : null ) ) { 
  330. $element->setAttribute( 'required', 'required' ); 
  331.  
  332. // Process name first. 
  333. if ( $element = (( $result = $xpath->query( "//input[@id='{$field_uid}_3']" )) ? $result->item( 0 ) : null ) ) { 
  334. $element->setAttribute( 'required', 'required' ); 
  335.  
  336. // Process name last. 
  337. if ( $element = (( $result = $xpath->query( "//input[@id='{$field_uid}_6']" )) ? $result->item( 0 ) : null ) ) { 
  338. $element->setAttribute( 'required', 'required' ); 
  339.  
  340. // Process name suffix. 
  341. $name_suffix_required = apply_filters( "gform_name_suffix_required_{$form_id}", apply_filters( 'gform_name_suffix_required', false, $form_id ), $form_id ); 
  342. if ( 'extended' === $name_format && $name_suffix_required ) { 
  343. if ( $element = (( $result = $xpath->query( "//input[@id='{$field_uid}_8']" )) ? $result->item( 0 ) : null ) ) { 
  344. $element->setAttribute( 'required', 'required' ); 
  345.  
  346. break; // End normal and extended format. 
  347.  
  348. case 'advanced': 
  349.  
  350. $filters = array( 
  351. "{$field_id}.2" => 'gform_name_prefix_required',  
  352. "{$field_id}.4" => 'gform_name_middle_required',  
  353. "{$field_id}.8" => 'gform_name_suffix_required',  
  354. ); 
  355.  
  356. $inputs = rgar( $field, 'inputs', array() ); 
  357. foreach ( $inputs as $input ) { 
  358. $is_hidden = rgar( $input, 'isHidden', false ); 
  359. if ( false === $is_hidden ) { 
  360. $input_id = rgar( $input, 'id', false ); 
  361. if ( is_string( $input_id ) ) { 
  362. $element_required = array_key_exists( $input_id, $filters ) ? apply_filters( $filters[ $input_id ] . '_' . $form_id, apply_filters( $filters[ $input_id ], false, $form_id ), $form_id ) : true; 
  363. if ( $element_required ) { 
  364. if ( $element = ( ( $result = $xpath->query( "//input[@name='input_{$input_id}']" ) ) ? $result->item( 0 ) : null ) ) { 
  365. $element->setAttribute( 'required', 'required' ); 
  366. break; // End advanced format. 
  367.  
  368. } // End switch. 
  369.  
  370. break; // End name field. 
  371.  
  372. case 'address': 
  373.  
  374. // Process address line 1. 
  375. if ( $element = (($result = $xpath->query( "//input[@id='{$field_uid}_1']" )) ? $result->item( 0 ) : null) ) { 
  376. $element->setAttribute( 'required', 'required' ); 
  377.  
  378. // Process address line 2. 
  379. $street2_hidden = rgar( $field, 'hideAddress2', false ); 
  380. $street2_required = apply_filters( "gform_address_street2_required_{$form_id}", apply_filters( 'gform_address_street2_required', false, $form_id ), $form_id ); 
  381. if ( false === $street2_hidden && true === $street2_required ) { 
  382. if ( $element = (($result = $xpath->query( "//input[@id='{$field_uid}_2']" )) ? $result->item( 0 ) : null) ) { 
  383. $element->setAttribute( 'required', 'required' ); 
  384.  
  385. // Process address city. 
  386. if ( $element = (($result = $xpath->query( "//input[@id='{$field_uid}_3']" )) ? $result->item( 0 ) : null) ) { 
  387. $element->setAttribute( 'required', 'required' ); 
  388.  
  389. // Process address state / province. 
  390. $state_hidden = rgar( $field, 'hideState', false ); 
  391. if ( false === $state_hidden ) { 
  392. if ( $element = (($result = $xpath->query( "//input[@id='{$field_uid}_4']" )) ? $result->item( 0 ) : null) ) { 
  393. $element->setAttribute( 'required', 'required' ); 
  394.  
  395. // Process address zip / postal. 
  396. if ( $element = (($result = $xpath->query( "//input[@id='{$field_uid}_5']" )) ? $result->item( 0 ) : null) ) { 
  397. $element->setAttribute( 'required', 'required' ); 
  398.  
  399. // Process address country. 
  400. $country_hidden = rgar( $field, 'hideCountry', false ); 
  401. if ( false === $country_hidden ) { 
  402. if ( $element = (($result = $xpath->query( "//select[@id='{$field_uid}_6']" )) ? $result->item( 0 ) : null) ) { 
  403. $element->setAttribute( 'required', 'required' ); 
  404.  
  405. break; // End address field. 
  406.  
  407. case 'date': 
  408.  
  409. $date_type = rgar( $field, 'dateType', 'datepicker' ); 
  410. switch ( $date_type ) { 
  411.  
  412. case 'datepicker': 
  413.  
  414. // Process date picker. 
  415. if ( $element = (($result = $xpath->query( "//input[@id='{$field_uid}']" )) ? $result->item( 0 ) : null) ) { 
  416. $element->setAttribute( 'required', 'required' ); 
  417.  
  418. break; // End datepicker type. 
  419.  
  420. case 'datefield': 
  421.  
  422. // Process date month. 
  423. if ( $element = (($result = $xpath->query( "//input[@id='{$field_uid}_1']" )) ? $result->item( 0 ) : null) ) { 
  424. $element->setAttribute( 'required', 'required' ); 
  425.  
  426. // Process date day. 
  427. if ( $element = (($result = $xpath->query( "//input[@id='{$field_uid}_2']" )) ? $result->item( 0 ) : null) ) { 
  428. $element->setAttribute( 'required', 'required' ); 
  429.  
  430. // Process date year. 
  431. if ( $element = (($result = $xpath->query( "//input[@id='{$field_uid}_3']" )) ? $result->item( 0 ) : null) ) { 
  432. $element->setAttribute( 'required', 'required' ); 
  433.  
  434. break; // End datefield type. 
  435.  
  436. } // End switch. 
  437.  
  438. break; // End date field. 
  439.  
  440. case 'time': 
  441.  
  442. // Process time hour. 
  443. if ( $element = (($result = $xpath->query( "//input[@id='{$field_uid}_1']" )) ? $result->item( 0 ) : null) ) { 
  444. $element->setAttribute( 'required', 'required' ); 
  445.  
  446. // Process time minute. 
  447. if ( $element = (($result = $xpath->query( "//input[@id='{$field_uid}_2']" )) ? $result->item( 0 ) : null) ) { 
  448. $element->setAttribute( 'required', 'required' ); 
  449.  
  450. break; // End time field. 
  451.  
  452. case 'product': 
  453. case 'singleproduct': 
  454. case 'calculation': 
  455.  
  456. $product_disable_quantity = rgar( $field, 'disableQuantity', false ); 
  457. if ( ! $product_disable_quantity ) { 
  458. if ( $element = (($result = $xpath->query( "//input[@name='input_{$field_id}.3']" )) ? $result->item( 0 ) : null) ) { 
  459. $element->setAttribute( 'required', 'required' ); 
  460.  
  461. break; // End product, singleproduct & caclulation field. 
  462.  
  463. case 'quantity': 
  464.  
  465. $quantity_type = rgar( $field, 'inputType', 'number' ); 
  466. switch ( $quantity_type ) { 
  467.  
  468. case 'number': 
  469.  
  470. // Process Product Amount. 
  471. if ( $element = (($result = $xpath->query( "//input[@id='{$field_uid}']" )) ? $result->item( 0 ) : null) ) { 
  472. $element->setAttribute( 'required', 'required' ); 
  473.  
  474. break; // End number type. 
  475.  
  476. break; // End quantity field. 
  477.  
  478. case 'creditcard': 
  479.  
  480. // Process card number. 
  481. if ( $element = (( $result = $xpath->query( "//input[@id='{$field_uid}_1']" )) ? $result->item( 0 ) : null ) ) { 
  482. $element->setAttribute( 'required', 'required' ); 
  483.  
  484. // Process expiration month. 
  485. if ( $element = (( $result = $xpath->query( "//select[@id='{$field_uid}_2_month']" )) ? $result->item( 0 ) : null ) ) { 
  486. $element->setAttribute( 'required', 'required' ); 
  487.  
  488. // Process expiration year. 
  489. if ( $element = (( $result = $xpath->query( "//select[@id='{$field_uid}_2_year']" )) ? $result->item( 0 ) : null ) ) { 
  490. $element->setAttribute( 'required', 'required' ); 
  491.  
  492. // Process security code. 
  493. if ( $element = (( $result = $xpath->query( "//input[@id='{$field_uid}_3']" )) ? $result->item( 0 ) : null ) ) { 
  494. $element->setAttribute( 'required', 'required' ); 
  495.  
  496. // Process card holder name. 
  497. if ( $element = (( $result = $xpath->query( "//input[@id='{$field_uid}_5']" )) ? $result->item( 0 ) : null ) ) { 
  498. $element->setAttribute( 'required', 'required' ); 
  499. break; 
  500.  
  501. $field_content = $doc->SaveHTML(); 
  502.  
  503. // Remove our html wrapper from processed field. 
  504. $field_content = str_replace( 
  505. array( '<html>', '</html>', '<head>', '</head>', '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">', '<body>', '</body>' ),  
  506. array( '', '', '', '', '', '', '' ),  
  507. $field_content 
  508. ); 
  509.  
  510. $field_content = trim( preg_replace( '/^<!DOCTYPE.+?>/', '', $field_content ) ); 
  511.  
  512. // Check if we are currently on ajax and fix double quotes to single. 
  513. if ( defined( 'RG_CURRENT_PAGE' ) && RG_CURRENT_PAGE === 'admin-ajax.php' ) { 
  514.  
  515. // Replace non escaped double quotes with single quotes for ajax support. 
  516. $matches = array(); 
  517. preg_match_all( '/"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"/s', $field_content, $matches ); 
  518. if ( count( $matches[0] ) > 0 ) { 
  519. foreach ( $matches[0] as $match ) { 
  520. $replace = "'" . substr( $match, 1 , strlen( $match ) - 2 ) . "'"; 
  521. $field_content = str_replace( $match, $replace, $field_content ); 
  522.  
  523. // Restore libxml error handling. 
  524. libxml_use_internal_errors( $use_errors ); 
  525.  
  526. return $field_content; 
  527.  
  528. /** 
  529. * Target of wp_enqueue_scripts hooks. 
  530. * @param mixed $form The current form object. 
  531. * @param bool $ajax A boolean value indicating whether this is an ajax call. 
  532. * @return void 
  533. */ 
  534. public function gform_enqueue_scripts( $form, $ajax = false ) { 
  535. if ( $this->is_gravityforms_html5_enabled() ) { 
  536.  
  537. // Determine whether to use minified script versions. 
  538. $min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; 
  539.  
  540. // Register our scripts and styles 
  541. wp_enqueue_script( 
  542. 'gravityforms-html5-validation',  
  543. $this->get_base_url( "/js/gravityforms-html5-validation{$min}.js" ),  
  544. array( 'jquery' ),  
  545. $this->version,  
  546. false 
  547. ); 
  548.  
  549.  
  550. /** 
  551. * Target of gform_next_button. 
  552. * Manipulate next buttons on paginated forms. 
  553. * @param string $button The next button content. 
  554. * @param array $form The current form object. 
  555. * @return string 
  556. */ 
  557. public function gform_next_button( $button, $form ) { 
  558. if ( $this->is_gravityforms_html5_enabled() && rgar( $form, 'pagination', false ) ) { 
  559. $button = preg_replace_callback( "/(.*onclick=')(.*)('.*)/", function( $m ) use ( $form ) { 
  560.  
  561. $p = array(); 
  562. preg_match( '/jQuery\("#gform_target_page_number_'.$form['id'].'"\).val\("(.*)"\);/', $m[2], $p ); 
  563.  
  564. return $m[1].$p[0].' Html5ValidatePage('.$form['id'].', jQuery(this).closest(".gform_page"));'.$m[3]; 
  565.  
  566. }, $button ); 
  567. return $button; 
  568.  
  569. /** 
  570. * Target of gform_submit_button. 
  571. * Manipulate next buttons on paginated forms. 
  572. * @param string $button The next button content. 
  573. * @param array $form The current form object. 
  574. * @return string 
  575. */ 
  576. public function gform_submit_button( $button, $form ) { 
  577. if ( $this->is_gravityforms_html5_enabled() && rgar( $form, 'pagination', false ) ) { 
  578. $button = preg_replace_callback( "/(.*onclick=')(.*)('.*)/", function( $m ) use ( $form ) { 
  579.  
  580. return $m[1].'if(window["gf_submitting_'.$form['id'].'"]) {return false;} if(Html5ValidatePage('.$form['id'].', jQuery(this).closest(".gform_page")) ) {window["gf_submitting_'.$form['id'].'"]=true;}'.$m[3]; 
  581.  
  582. }, $button ); 
  583. return $button; 
  584.  
  585. /** 
  586. * Target of admin_notices action. 
  587. * @return void 
  588. */ 
  589. public function render_warnings() { 
  590.  
  591. $screen = get_current_screen(); 
  592. $messages = array(); 
  593.  
  594. if ( array_key_exists( 'all', $this->warnings ) ) { 
  595. $messages = array_merge( $messages, $this->warnings['all'] ); 
  596.  
  597. if ( array_key_exists( $screen->id, $this->warnings ) ) { 
  598. $messages = array_merge( $messages, $this->warnings[ $screen->id ] ); 
  599.  
  600. foreach ( $messages as $message ) { 
  601. echo '<div class="message error"><p>'.$message.'</p></div>'; 
  602.  
  603. /** 
  604. * Target of admin_enqueue_scripts. 
  605. * @return void 
  606. */ 
  607. public function enqueue_scripts_admin() { 
  608. // NOOP: To be used later. 
  609.  
  610. #endregion Action/Filter Target Methods 
  611.  
  612. #region Helper Methods 
  613.  
  614. /** 
  615. * Add a warning message. 
  616. * @param string $message The message to show. 
  617. * @param string $page Optional. The target page. Defaults to all. 
  618. * @return void 
  619. */ 
  620. protected function add_warning( $message, $page = 'all' ) { 
  621. if ( is_string( $message ) && ! empty( $message ) ) { 
  622.  
  623. if ( empty( $page ) ) { 
  624. $page = 'all'; 
  625.  
  626. if ( ! isset( $this->warnings[ $page ] ) ) { 
  627. $this->warnings[ $page ] = array(); 
  628.  
  629. $this->warnings[ $page ][] = $message; 
  630.  
  631. /** 
  632. * Returns the url of the root folder of the current Add-On. 
  633. * @param string $extra_path Optional. Extra path appended to the base path. Default is empty string. 
  634. * @return string 
  635. */ 
  636. protected function get_base_url( $extra_path = '' ) { 
  637.  
  638. if ( ! is_string( $extra_path ) ) { 
  639. $extra_path = ''; 
  640.  
  641. $plugin_url = untrailingslashit( plugins_url( '/', __FILE__ ) ); 
  642.  
  643. if ( ! empty( $extra_path ) ) { 
  644. $extra_path = trim( $extra_path, DIRECTORY_SEPARATOR ); 
  645. return join( DIRECTORY_SEPARATOR, array( $plugin_url, $extra_path ) ); 
  646.  
  647. return $plugin_url; 
  648.  
  649.  
  650. /** 
  651. * Returns the path of the root folder of the current Add-On. 
  652. * @param string $extra_path Optional. Extra path appended to the base path. Default is empty string. 
  653. * @return string 
  654. */ 
  655. protected function get_base_path( $extra_path = '' ) { 
  656.  
  657. if ( ! is_string( $extra_path ) ) { 
  658. $extra_path = ''; 
  659.  
  660. $plugin_path = untrailingslashit( plugin_dir_path( __FILE__ ) ); 
  661.  
  662. if ( ! empty( $extra_path ) ) { 
  663. $extra_path = trim( $extra_path, DIRECTORY_SEPARATOR ); 
  664. return join( DIRECTORY_SEPARATOR, array( $plugin_path, $extra_path ) ); 
  665.  
  666. return $plugin_path; 
  667.  
  668. /** 
  669. * Returns an html formatted form tooltip. 
  670. * @param string $title The tooltip title. 
  671. * @param string $description The tooltip title. 
  672. * @return string 
  673. */ 
  674. protected function generate_tooltip( $title, $description ) { 
  675. $tooltip = ''; 
  676. if ( is_string( $title ) ) { 
  677. $tooltip .= "<h6>{$title}</h6>"; 
  678. if ( is_string( $description ) ) { 
  679. $tooltip .= $description; 
  680. return $tooltip; 
  681.  
  682. /** 
  683. * Get the contents of a template file. 
  684. * @param string $filename The template part filename. 
  685. * @param array $data The template part data. 
  686. * @return string The rendered template part. 
  687. */ 
  688. protected function get_template_part( $filename, array $data = array() ) { 
  689.  
  690. extract( $data ); 
  691.  
  692. ob_start(); 
  693. include( $this->get_base_path( 'templates' . DIRECTORY_SEPARATOR . $filename ) ); 
  694. $template = ob_get_contents(); 
  695. ob_end_clean(); 
  696.  
  697. return $template; 
  698.  
  699. /** 
  700. * Determine whether we are currently in the form editor page. 
  701. * @return bool True if the current page is the form editor page; Otherwise, false. 
  702. */ 
  703. public function is_form_editor() { 
  704. if ( class_exists( '\GFCommon' ) ) { 
  705. return \GFCommon::is_form_editor(); 
  706. return false; 
  707.  
  708. /** 
  709. * Determine whether the Gravity Forms is installed. 
  710. * @return bool True if Gravity Forms is installed; Otherwise false. 
  711. */ 
  712. public function is_gravityforms_installed() { 
  713. return class_exists( '\GFForms' ); 
  714.  
  715. /** 
  716. * Determine whether the Gravity Forms HTML5 output is enabled. 
  717. * @return bool True if Gravity Forms HTML5 output is enabled; Otherwise false. 
  718. */ 
  719. public function is_gravityforms_html5_enabled() { 
  720. if ( class_exists( '\RGFormsModel' ) ) { 
  721. return (bool) \RGFormsModel::is_html5_enabled(); 
  722. return false; 
  723.  
  724. /** 
  725. * Determine whether the current version of Gravity Forms is supported. 
  726. * @param string $min_version Optional. The minimum version to check. Defaults to the plugin minimum Gravity Forms version if set. 
  727. * @return bool True if the current version of Gravity Forms is supported; Otherwise false. 
  728. */ 
  729. public function is_gravityforms_supported( $min_version = '' ) { 
  730.  
  731. if ( isset( $this->min_gravityforms_version ) && empty( $min_version ) ) { 
  732. $min_version = $this->min_gravityforms_version; 
  733.  
  734. if ( empty( $min_version ) ) { 
  735. return true; 
  736.  
  737. if ( class_exists( '\GFCommon' ) ) { 
  738. return version_compare( \GFCommon::$version, $min_version, '>=' ); 
  739.  
  740. return false; 
  741.  
  742. /** 
  743. * Determine whether the current version of WordPress is supported. 
  744. * @param string $min_version Optional; The minimum version to check. Defaults to the plugin minimum WordPress version if set. 
  745. * @return bool True if the current version of WordPress is supported. Otherwise false. 
  746. */ 
  747. public function is_wordpress_supported( $min_version = '' ) { 
  748.  
  749. if ( isset( $this->min_wordpress_version ) && empty( $min_version ) ) { 
  750. $min_version = $this->min_wordpress_version; 
  751.  
  752. if ( empty( $min_version ) ) { 
  753. return true; 
  754.  
  755. if ( function_exists( 'get_bloginfo' ) ) { 
  756. return version_compare( get_bloginfo( 'version' ), $min_version, '>=' ); 
  757.  
  758. return false; 
  759.  
  760. /** 
  761. * Log a message. 
  762. * @param string $message The message to log. 
  763. * @param mixed $attachment Optional. An attachment to the message. Defaults to null. 
  764. * @return void 
  765. */ 
  766. protected function log( $message, $attachment = null ) { 
  767.  
  768. if ( ! $this->debug ) { 
  769. return; 
  770.  
  771. if ( defined( 'DOING_AJAX' ) ) { 
  772. $call_mode = 'WP_AJAX'; 
  773. } elseif ( defined( 'RG_CURRENT_PAGE' ) && RG_CURRENT_PAGE === 'admin-ajax.php' ) { 
  774. $call_mode = 'GF_AJAX'; 
  775. } else { 
  776. $call_mode = 'NORMAL'; 
  777.  
  778. $user_mode = defined( 'IS_ADMIN' ) ? 'ADMIN' : 'NORMAL'; 
  779.  
  780. $timestamp = date( 'Y-m-d H:i:s' ); 
  781. $log = "[ {$timestamp} ][ $call_mode ][ $user_mode ][ $message ]\r\n\n"; 
  782.  
  783. if ( isset( $attachment ) ) { 
  784.  
  785. $type = gettype( $attachment ); 
  786. switch ( $type ) { 
  787. case 'array': 
  788. case 'object': 
  789. $log .= print_r( $attachment, true ); 
  790. break; 
  791.  
  792. default: 
  793. $log .= (string) $attachment; 
  794. break; 
  795. $log .= "\r\n\n"; 
  796.  
  797. $logfile = $this->get_base_path( 'debug.log' ); 
  798. file_put_contents( $logfile , $log , FILE_APPEND ); 
  799.  
  800. #endregion Helper Methods