validation.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. <?php
  2. if ( ! defined( 'ABSPATH' ) ) {
  3. exit; // Exit if accessed directly
  4. }
  5. if ( ! class_exists( 'acf_validation' ) ) :
  6. class acf_validation {
  7. /*
  8. * __construct
  9. *
  10. * This function will setup the class functionality
  11. *
  12. * @type function
  13. * @date 5/03/2014
  14. * @since 5.0.0
  15. *
  16. * @param n/a
  17. * @return n/a
  18. */
  19. function __construct() {
  20. // vars
  21. $this->errors = array();
  22. // ajax
  23. add_action( 'wp_ajax_acf/validate_save_post', array( $this, 'ajax_validate_save_post' ) );
  24. add_action( 'wp_ajax_nopriv_acf/validate_save_post', array( $this, 'ajax_validate_save_post' ) );
  25. add_action( 'acf/validate_save_post', array( $this, 'acf_validate_save_post' ), 5 );
  26. }
  27. /*
  28. * add_error
  29. *
  30. * This function will add an error message for a field
  31. *
  32. * @type function
  33. * @date 25/11/2013
  34. * @since 5.0.0
  35. *
  36. * @param $input (string) name attribute of DOM elmenet
  37. * @param $message (string) error message
  38. * @return $post_id (int)
  39. */
  40. function add_error( $input, $message ) {
  41. // add to array
  42. $this->errors[] = array(
  43. 'input' => $input,
  44. 'message' => $message,
  45. );
  46. }
  47. /*
  48. * get_error
  49. *
  50. * This function will return an error for a given input
  51. *
  52. * @type function
  53. * @date 5/03/2016
  54. * @since 5.3.2
  55. *
  56. * @param $input (string) name attribute of DOM elmenet
  57. * @return (mixed)
  58. */
  59. function get_error( $input ) {
  60. // bail early if no errors
  61. if ( empty( $this->errors ) ) {
  62. return false;
  63. }
  64. // loop
  65. foreach ( $this->errors as $error ) {
  66. if ( $error['input'] === $input ) {
  67. return $error;
  68. }
  69. }
  70. // return
  71. return false;
  72. }
  73. /*
  74. * get_errors
  75. *
  76. * This function will return validation errors
  77. *
  78. * @type function
  79. * @date 25/11/2013
  80. * @since 5.0.0
  81. *
  82. * @param n/a
  83. * @return (array|boolean)
  84. */
  85. function get_errors() {
  86. // bail early if no errors
  87. if ( empty( $this->errors ) ) {
  88. return false;
  89. }
  90. // return
  91. return $this->errors;
  92. }
  93. /*
  94. * reset_errors
  95. *
  96. * This function will remove all errors
  97. *
  98. * @type function
  99. * @date 4/03/2016
  100. * @since 5.3.2
  101. *
  102. * @param n/a
  103. * @return n/a
  104. */
  105. function reset_errors() {
  106. $this->errors = array();
  107. }
  108. /*
  109. * ajax_validate_save_post
  110. *
  111. * This function will validate the $_POST data via AJAX
  112. *
  113. * @type function
  114. * @date 27/10/2014
  115. * @since 5.0.9
  116. *
  117. * @param n/a
  118. * @return n/a
  119. */
  120. function ajax_validate_save_post() {
  121. // validate
  122. if ( ! acf_verify_ajax() ) {
  123. die();
  124. }
  125. // vars
  126. $json = array(
  127. 'valid' => 1,
  128. 'errors' => 0,
  129. );
  130. // success
  131. if ( acf_validate_save_post() ) {
  132. wp_send_json_success( $json );
  133. }
  134. // update vars
  135. $json['valid'] = 0;
  136. $json['errors'] = acf_get_validation_errors();
  137. // return
  138. wp_send_json_success( $json );
  139. }
  140. /*
  141. * acf_validate_save_post
  142. *
  143. * This function will loop over $_POST data and validate
  144. *
  145. * @type function
  146. * @date 7/09/2016
  147. * @since 5.4.0
  148. *
  149. * @param n/a
  150. * @return n/a
  151. */
  152. function acf_validate_save_post() {
  153. // phpcs:disable WordPress.Security.NonceVerification.Missing -- Verified elsewhere.
  154. // bail early if no $_POST
  155. if ( empty( $_POST['acf'] ) ) {
  156. return;
  157. }
  158. // validate
  159. acf_validate_values( $_POST['acf'], 'acf' ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
  160. // phpcs:enable WordPress.Security.NonceVerification.Missing
  161. }
  162. }
  163. // initialize
  164. acf()->validation = new acf_validation();
  165. endif; // class_exists check
  166. /*
  167. * Public functions
  168. *
  169. * alias of acf()->validation->function()
  170. *
  171. * @type function
  172. * @date 6/10/13
  173. * @since 5.0.0
  174. *
  175. * @param n/a
  176. * @return n/a
  177. */
  178. function acf_add_validation_error( $input, $message = '' ) {
  179. return acf()->validation->add_error( $input, $message );
  180. }
  181. function acf_get_validation_errors() {
  182. return acf()->validation->get_errors();
  183. }
  184. function acf_get_validation_error() {
  185. return acf()->validation->get_error( $input );
  186. }
  187. function acf_reset_validation_errors() {
  188. return acf()->validation->reset_errors();
  189. }
  190. /*
  191. * acf_validate_save_post
  192. *
  193. * This function will validate $_POST data and add errors
  194. *
  195. * @type function
  196. * @date 25/11/2013
  197. * @since 5.0.0
  198. *
  199. * @param $show_errors (boolean) if true, errors will be shown via a wp_die screen
  200. * @return (boolean)
  201. */
  202. function acf_validate_save_post( $show_errors = false ) {
  203. // action
  204. do_action( 'acf/validate_save_post' );
  205. // vars
  206. $errors = acf_get_validation_errors();
  207. // bail early if no errors
  208. if ( ! $errors ) {
  209. return true;
  210. }
  211. // show errors
  212. if ( $show_errors ) {
  213. $message = '<h2>' . __( 'Validation failed', 'acf' ) . '</h2>';
  214. $message .= '<ul>';
  215. foreach ( $errors as $error ) {
  216. $message .= '<li>' . $error['message'] . '</li>';
  217. }
  218. $message .= '</ul>';
  219. // die
  220. wp_die( $message, __( 'Validation failed', 'acf' ) );
  221. }
  222. // return
  223. return false;
  224. }
  225. /*
  226. * acf_validate_values
  227. *
  228. * This function will validate an array of field values
  229. *
  230. * @type function
  231. * @date 6/10/13
  232. * @since 5.0.0
  233. *
  234. * @param values (array)
  235. * @param $input_prefix (string)
  236. * @return n/a
  237. */
  238. function acf_validate_values( $values, $input_prefix = '' ) {
  239. // bail early if empty
  240. if ( empty( $values ) ) {
  241. return;
  242. }
  243. // loop
  244. foreach ( $values as $key => $value ) {
  245. // vars
  246. $field = acf_get_field( $key );
  247. $input = $input_prefix . '[' . $key . ']';
  248. // bail early if not found
  249. if ( ! $field ) {
  250. continue;
  251. }
  252. // validate
  253. acf_validate_value( $value, $field, $input );
  254. }
  255. }
  256. /*
  257. * acf_validate_value
  258. *
  259. * This function will validate a field's value
  260. *
  261. * @type function
  262. * @date 6/10/13
  263. * @since 5.0.0
  264. *
  265. * @param n/a
  266. * @return n/a
  267. */
  268. function acf_validate_value( $value, $field, $input ) {
  269. // vars
  270. $valid = true;
  271. $message = sprintf( __( '%s value is required', 'acf' ), $field['label'] );
  272. // valid
  273. if ( $field['required'] ) {
  274. // valid is set to false if the value is empty, but allow 0 as a valid value
  275. if ( empty( $value ) && ! is_numeric( $value ) ) {
  276. $valid = false;
  277. }
  278. }
  279. /**
  280. * Filters whether the value is valid.
  281. *
  282. * @date 28/09/13
  283. * @since 5.0.0
  284. *
  285. * @param bool $valid The valid status. Return a string to display a custom error message.
  286. * @param mixed $value The value.
  287. * @param array $field The field array.
  288. * @param string $input The input element's name attribute.
  289. */
  290. $valid = apply_filters( "acf/validate_value/type={$field['type']}", $valid, $value, $field, $input );
  291. $valid = apply_filters( "acf/validate_value/name={$field['_name']}", $valid, $value, $field, $input );
  292. $valid = apply_filters( "acf/validate_value/key={$field['key']}", $valid, $value, $field, $input );
  293. $valid = apply_filters( 'acf/validate_value', $valid, $value, $field, $input );
  294. // allow $valid to be a custom error message
  295. if ( ! empty( $valid ) && is_string( $valid ) ) {
  296. $message = $valid;
  297. $valid = false;
  298. }
  299. if ( ! $valid ) {
  300. acf_add_validation_error( $input, $message );
  301. return false;
  302. }
  303. // return
  304. return true;
  305. }