acf-input-functions.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. <?php
  2. /**
  3. * acf_filter_attrs
  4. *
  5. * Filters out empty attrs from the provided array.
  6. *
  7. * @date 11/6/19
  8. * @since 5.8.1
  9. *
  10. * @param array $attrs The array of attrs.
  11. * @return array
  12. */
  13. function acf_filter_attrs( $attrs ) {
  14. // Filter out empty attrs but allow "0" values.
  15. $filtered = array_filter( $attrs, 'acf_not_empty' );
  16. // Correct specific attributes (required="required").
  17. foreach ( array( 'required', 'readonly', 'disabled', 'multiple' ) as $key ) {
  18. unset( $filtered[ $key ] );
  19. if ( ! empty( $attrs[ $key ] ) ) {
  20. $filtered[ $key ] = $key;
  21. }
  22. }
  23. return $filtered;
  24. }
  25. /**
  26. * acf_esc_attrs
  27. *
  28. * Generated valid HTML from an array of attrs.
  29. *
  30. * @date 11/6/19
  31. * @since 5.8.1
  32. *
  33. * @param array $attrs The array of attrs.
  34. * @return string
  35. */
  36. function acf_esc_attrs( $attrs ) {
  37. $html = '';
  38. // Loop over attrs and validate data types.
  39. foreach ( $attrs as $k => $v ) {
  40. // String (but don't trim value).
  41. if ( is_string( $v ) && ( $k !== 'value' ) ) {
  42. $v = trim( $v );
  43. // Boolean
  44. } elseif ( is_bool( $v ) ) {
  45. $v = $v ? 1 : 0;
  46. // Object
  47. } elseif ( is_array( $v ) || is_object( $v ) ) {
  48. $v = json_encode( $v );
  49. }
  50. // Generate HTML.
  51. $html .= sprintf( ' %s="%s"', esc_attr( $k ), esc_attr( $v ) );
  52. }
  53. // Return trimmed.
  54. return trim( $html );
  55. }
  56. /**
  57. * Sanitizes text content and strips out disallowed HTML.
  58. *
  59. * This function emulates `wp_kses_post()` with a context of "acf" for extensibility.
  60. *
  61. * @date 16/4/21
  62. * @since 5.9.6
  63. *
  64. * @param string $string
  65. * @return string
  66. */
  67. function acf_esc_html( $string = '' ) {
  68. return wp_kses( (string) $string, 'acf' );
  69. }
  70. /**
  71. * Private callback for the "wp_kses_allowed_html" filter used to return allowed HTML for "acf" context.
  72. *
  73. * @date 16/4/21
  74. * @since 5.9.6
  75. *
  76. * @param array $tags An array of allowed tags.
  77. * @param string $context The context name.
  78. * @return array.
  79. */
  80. function _acf_kses_allowed_html( $tags, $context ) {
  81. global $allowedposttags;
  82. if ( $context === 'acf' ) {
  83. return $allowedposttags;
  84. }
  85. return $tags;
  86. }
  87. add_filter( 'wp_kses_allowed_html', '_acf_kses_allowed_html', 0, 2 );
  88. /**
  89. * acf_html_input
  90. *
  91. * Returns the HTML of an input.
  92. *
  93. * @date 13/6/19
  94. * @since 5.8.1
  95. *
  96. * @param array $attrs The array of attrs.
  97. * @return string
  98. */
  99. // function acf_html_input( $attrs = array() ) {
  100. // return sprintf( '<input %s/>', acf_esc_attrs($attrs) );
  101. // }
  102. /**
  103. * acf_hidden_input
  104. *
  105. * Renders the HTML of a hidden input.
  106. *
  107. * @date 3/02/2014
  108. * @since 5.0.0
  109. *
  110. * @param array $attrs The array of attrs.
  111. * @return string
  112. */
  113. function acf_hidden_input( $attrs = array() ) {
  114. echo acf_get_hidden_input( $attrs );
  115. }
  116. /**
  117. * acf_get_hidden_input
  118. *
  119. * Returns the HTML of a hidden input.
  120. *
  121. * @date 3/02/2014
  122. * @since 5.0.0
  123. *
  124. * @param array $attrs The array of attrs.
  125. * @return string
  126. */
  127. function acf_get_hidden_input( $attrs = array() ) {
  128. return sprintf( '<input type="hidden" %s/>', acf_esc_attrs( $attrs ) );
  129. }
  130. /**
  131. * acf_text_input
  132. *
  133. * Renders the HTML of a text input.
  134. *
  135. * @date 3/02/2014
  136. * @since 5.0.0
  137. *
  138. * @param array $attrs The array of attrs.
  139. * @return string
  140. */
  141. function acf_text_input( $attrs = array() ) {
  142. echo acf_get_text_input( $attrs );
  143. }
  144. /**
  145. * acf_get_text_input
  146. *
  147. * Returns the HTML of a text input.
  148. *
  149. * @date 3/02/2014
  150. * @since 5.0.0
  151. *
  152. * @param array $attrs The array of attrs.
  153. * @return string
  154. */
  155. function acf_get_text_input( $attrs = array() ) {
  156. $attrs = wp_parse_args(
  157. $attrs,
  158. array(
  159. 'type' => 'text',
  160. )
  161. );
  162. if ( isset( $attrs['value'] ) && is_string( $attrs['value'] ) ) {
  163. $attrs['value'] = htmlspecialchars( $attrs['value'] );
  164. }
  165. return sprintf( '<input %s/>', acf_esc_attrs( $attrs ) );
  166. }
  167. /**
  168. * acf_file_input
  169. *
  170. * Renders the HTML of a file input.
  171. *
  172. * @date 3/02/2014
  173. * @since 5.0.0
  174. *
  175. * @param array $attrs The array of attrs.
  176. * @return string
  177. */
  178. function acf_file_input( $attrs = array() ) {
  179. echo acf_get_file_input( $attrs );
  180. }
  181. /**
  182. * acf_get_file_input
  183. *
  184. * Returns the HTML of a file input.
  185. *
  186. * @date 3/02/2014
  187. * @since 5.0.0
  188. *
  189. * @param array $attrs The array of attrs.
  190. * @return string
  191. */
  192. function acf_get_file_input( $attrs = array() ) {
  193. $field_key = isset( $attrs['key'] ) && is_string( $attrs['key'] ) ? $attrs['key'] : '';
  194. $nonce_field = '';
  195. /**
  196. * If we don't have a field key (most likely because this was called by a third-party field),
  197. * we have to try to guess the field key based on the field name.
  198. */
  199. if ( '' === $field_key ) {
  200. $parts = explode( '[', $attrs['name'] );
  201. if ( is_array( $parts ) && ! empty( $parts[1] ) ) {
  202. // Remove the trailing `]`.
  203. $field_key = substr( end( $parts ), 0, -1 );
  204. }
  205. }
  206. /**
  207. * We only output the nonce if we have a field key, as it's possible to render
  208. * the file input without a real field. But, basic uploaders that don't have any
  209. * custom logic will likely fail to upload anyway if they don't have a field key.
  210. */
  211. if ( '' !== $field_key ) {
  212. $nonce_attrs = array(
  213. 'name' => 'acf[' . $field_key . '_file_nonce]',
  214. 'value' => wp_create_nonce( 'acf/file_uploader_nonce/' . $field_key ),
  215. );
  216. $nonce_field = sprintf(
  217. '<input type="hidden" %s />',
  218. acf_esc_attrs( $nonce_attrs )
  219. );
  220. }
  221. return sprintf(
  222. '<input type="file" %1$s />%2$s',
  223. acf_esc_attrs( $attrs ),
  224. $nonce_field
  225. );
  226. }
  227. /**
  228. * acf_textarea_input
  229. *
  230. * Renders the HTML of a textarea input.
  231. *
  232. * @date 3/02/2014
  233. * @since 5.0.0
  234. *
  235. * @param array $attrs The array of attrs.
  236. * @return string
  237. */
  238. function acf_textarea_input( $attrs = array() ) {
  239. echo acf_get_textarea_input( $attrs );
  240. }
  241. /**
  242. * acf_get_textarea_input
  243. *
  244. * Returns the HTML of a textarea input.
  245. *
  246. * @date 3/02/2014
  247. * @since 5.0.0
  248. *
  249. * @param array $attrs The array of attrs.
  250. * @return string
  251. */
  252. function acf_get_textarea_input( $attrs = array() ) {
  253. $value = '';
  254. if ( isset( $attrs['value'] ) ) {
  255. $value = $attrs['value'];
  256. unset( $attrs['value'] );
  257. }
  258. return sprintf( '<textarea %s>%s</textarea>', acf_esc_attrs( $attrs ), esc_textarea( $value ) );
  259. }
  260. /**
  261. * acf_checkbox_input
  262. *
  263. * Renders the HTML of a checkbox input.
  264. *
  265. * @date 3/02/2014
  266. * @since 5.0.0
  267. *
  268. * @param array $attrs The array of attrs.
  269. * @return string
  270. */
  271. function acf_checkbox_input( $attrs = array() ) {
  272. echo acf_get_checkbox_input( $attrs );
  273. }
  274. /**
  275. * acf_get_checkbox_input
  276. *
  277. * Returns the HTML of a checkbox input.
  278. *
  279. * @date 3/02/2014
  280. * @since 5.0.0
  281. *
  282. * @param array $attrs The array of attrs.
  283. * @return string
  284. */
  285. function acf_get_checkbox_input( $attrs = array() ) {
  286. // Allow radio or checkbox type.
  287. $attrs = wp_parse_args(
  288. $attrs,
  289. array(
  290. 'type' => 'checkbox',
  291. )
  292. );
  293. // Get label.
  294. $label = '';
  295. if ( isset( $attrs['label'] ) ) {
  296. $label = $attrs['label'];
  297. unset( $attrs['label'] );
  298. }
  299. // Render.
  300. $checked = isset( $attrs['checked'] );
  301. return '<label' . ( $checked ? ' class="selected"' : '' ) . '><input ' . acf_esc_attr( $attrs ) . '/> ' . acf_esc_html( $label ) . '</label>';
  302. }
  303. /**
  304. * acf_radio_input
  305. *
  306. * Renders the HTML of a radio input.
  307. *
  308. * @date 3/02/2014
  309. * @since 5.0.0
  310. *
  311. * @param array $attrs The array of attrs.
  312. * @return string
  313. */
  314. function acf_radio_input( $attrs = array() ) {
  315. echo acf_get_radio_input( $attrs );
  316. }
  317. /**
  318. * acf_get_radio_input
  319. *
  320. * Returns the HTML of a radio input.
  321. *
  322. * @date 3/02/2014
  323. * @since 5.0.0
  324. *
  325. * @param array $attrs The array of attrs.
  326. * @return string
  327. */
  328. function acf_get_radio_input( $attrs = array() ) {
  329. $attrs['type'] = 'radio';
  330. return acf_get_checkbox_input( $attrs );
  331. }
  332. /**
  333. * acf_select_input
  334. *
  335. * Renders the HTML of a select input.
  336. *
  337. * @date 3/02/2014
  338. * @since 5.0.0
  339. *
  340. * @param array $attrs The array of attrs.
  341. * @return string
  342. */
  343. function acf_select_input( $attrs = array() ) {
  344. echo acf_get_select_input( $attrs );
  345. }
  346. /**
  347. * acf_select_input
  348. *
  349. * Returns the HTML of a select input.
  350. *
  351. * @date 3/02/2014
  352. * @since 5.0.0
  353. *
  354. * @param array $attrs The array of attrs.
  355. * @return string
  356. */
  357. function acf_get_select_input( $attrs = array() ) {
  358. $value = (array) acf_extract_var( $attrs, 'value' );
  359. $choices = (array) acf_extract_var( $attrs, 'choices' );
  360. return sprintf(
  361. '<select %s>%s</select>',
  362. acf_esc_attrs( $attrs ),
  363. acf_walk_select_input( $choices, $value )
  364. );
  365. }
  366. /**
  367. * acf_walk_select_input
  368. *
  369. * Returns the HTML of a select input's choices.
  370. *
  371. * @date 27/6/17
  372. * @since 5.6.0
  373. *
  374. * @param array $choices The choices to walk through.
  375. * @param array $values The selected choices.
  376. * @param array $depth The current walk depth.
  377. * @return string
  378. */
  379. function acf_walk_select_input( $choices = array(), $values = array(), $depth = 0 ) {
  380. $html = '';
  381. // Sanitize values for 'selected' matching (only once).
  382. if ( $depth == 0 ) {
  383. $values = array_map( 'esc_attr', $values );
  384. }
  385. // Loop over choices and append to html.
  386. if ( $choices ) {
  387. foreach ( $choices as $value => $label ) {
  388. // Multiple (optgroup)
  389. if ( is_array( $label ) ) {
  390. $html .= sprintf(
  391. '<optgroup label="%s">%s</optgroup>',
  392. esc_attr( $value ),
  393. acf_walk_select_input( $label, $values, $depth + 1 )
  394. );
  395. // single (option)
  396. } else {
  397. $attrs = array(
  398. 'value' => $value,
  399. );
  400. // If is selected.
  401. $pos = array_search( esc_attr( $value ), $values );
  402. if ( $pos !== false ) {
  403. $attrs['selected'] = 'selected';
  404. $attrs['data-i'] = $pos;
  405. }
  406. $html .= sprintf( '<option %s>%s</option>', acf_esc_attr( $attrs ), esc_html( $label ) );
  407. }
  408. }
  409. }
  410. return $html;
  411. }
  412. /**
  413. * acf_clean_atts
  414. *
  415. * See acf_filter_attrs().
  416. *
  417. * @date 3/10/17
  418. * @since 5.6.3
  419. *
  420. * @param array $attrs The array of attrs.
  421. * @return string
  422. */
  423. function acf_clean_atts( $attrs ) {
  424. return acf_filter_attrs( $attrs );
  425. }
  426. /**
  427. * acf_esc_atts
  428. *
  429. * See acf_esc_attrs().
  430. *
  431. * @date 27/6/17
  432. * @since 5.6.0
  433. *
  434. * @param array $attrs The array of attrs.
  435. * @return string
  436. */
  437. function acf_esc_atts( $attrs ) {
  438. return acf_esc_attrs( $attrs );
  439. }
  440. /**
  441. * acf_esc_attr
  442. *
  443. * See acf_esc_attrs().
  444. *
  445. * @date 13/6/19
  446. * @since 5.8.1
  447. * @deprecated 5.6.0
  448. *
  449. * @param array $attrs The array of attrs.
  450. * @return string
  451. */
  452. function acf_esc_attr( $attrs ) {
  453. return acf_esc_attrs( $attrs );
  454. }
  455. /**
  456. * acf_esc_attr_e
  457. *
  458. * See acf_esc_attrs().
  459. *
  460. * @date 13/6/19
  461. * @since 5.8.1
  462. * @deprecated 5.6.0
  463. *
  464. * @param array $attrs The array of attrs.
  465. * @return string
  466. */
  467. function acf_esc_attr_e( $attrs ) {
  468. echo acf_esc_attrs( $attrs );
  469. }
  470. /**
  471. * acf_esc_atts_e
  472. *
  473. * See acf_esc_attrs().
  474. *
  475. * @date 13/6/19
  476. * @since 5.8.1
  477. * @deprecated 5.6.0
  478. *
  479. * @param array $attrs The array of attrs.
  480. * @return string
  481. */
  482. function acf_esc_atts_e( $attrs ) {
  483. echo acf_esc_attrs( $attrs );
  484. }