Brak opisu

class-acf-field-file.php 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. <?php
  2. if ( ! class_exists( 'acf_field_file' ) ) :
  3. class acf_field_file extends acf_field {
  4. /*
  5. * __construct
  6. *
  7. * This function will setup the field type data
  8. *
  9. * @type function
  10. * @date 5/03/2014
  11. * @since 5.0.0
  12. *
  13. * @param n/a
  14. * @return n/a
  15. */
  16. function initialize() {
  17. // vars
  18. $this->name = 'file';
  19. $this->label = __( 'File', 'acf' );
  20. $this->category = 'content';
  21. $this->defaults = array(
  22. 'return_format' => 'array',
  23. 'library' => 'all',
  24. 'min_size' => 0,
  25. 'max_size' => 0,
  26. 'mime_types' => '',
  27. );
  28. // filters
  29. add_filter( 'get_media_item_args', array( $this, 'get_media_item_args' ) );
  30. }
  31. /*
  32. * input_admin_enqueue_scripts
  33. *
  34. * description
  35. *
  36. * @type function
  37. * @date 16/12/2015
  38. * @since 5.3.2
  39. *
  40. * @param $post_id (int)
  41. * @return $post_id (int)
  42. */
  43. function input_admin_enqueue_scripts() {
  44. // localize
  45. acf_localize_text(
  46. array(
  47. 'Select File' => __( 'Select File', 'acf' ),
  48. 'Edit File' => __( 'Edit File', 'acf' ),
  49. 'Update File' => __( 'Update File', 'acf' ),
  50. )
  51. );
  52. }
  53. /*
  54. * render_field()
  55. *
  56. * Create the HTML interface for your field
  57. *
  58. * @param $field - an array holding all the field's data
  59. *
  60. * @type action
  61. * @since 3.6
  62. * @date 23/01/13
  63. */
  64. function render_field( $field ) {
  65. // vars
  66. $uploader = acf_get_setting( 'uploader' );
  67. // allow custom uploader
  68. $uploader = acf_maybe_get( $field, 'uploader', $uploader );
  69. // enqueue
  70. if ( $uploader == 'wp' ) {
  71. acf_enqueue_uploader();
  72. }
  73. // vars
  74. $o = array(
  75. 'icon' => '',
  76. 'title' => '',
  77. 'url' => '',
  78. 'filename' => '',
  79. 'filesize' => '',
  80. );
  81. $div = array(
  82. 'class' => 'acf-file-uploader',
  83. 'data-library' => $field['library'],
  84. 'data-mime_types' => $field['mime_types'],
  85. 'data-uploader' => $uploader,
  86. );
  87. // has value?
  88. if ( $field['value'] ) {
  89. $attachment = acf_get_attachment( $field['value'] );
  90. if ( $attachment ) {
  91. // has value
  92. $div['class'] .= ' has-value';
  93. // update
  94. $o['icon'] = $attachment['icon'];
  95. $o['title'] = $attachment['title'];
  96. $o['url'] = $attachment['url'];
  97. $o['filename'] = $attachment['filename'];
  98. if ( $attachment['filesize'] ) {
  99. $o['filesize'] = size_format( $attachment['filesize'] );
  100. }
  101. }
  102. }
  103. ?>
  104. <div <?php acf_esc_attr_e( $div ); ?>>
  105. <?php
  106. acf_hidden_input(
  107. array(
  108. 'name' => $field['name'],
  109. 'value' => $field['value'],
  110. 'data-name' => 'id',
  111. )
  112. );
  113. ?>
  114. <div class="show-if-value file-wrap">
  115. <div class="file-icon">
  116. <img data-name="icon" src="<?php echo esc_url( $o['icon'] ); ?>" alt=""/>
  117. </div>
  118. <div class="file-info">
  119. <p>
  120. <strong data-name="title"><?php echo esc_html( $o['title'] ); ?></strong>
  121. </p>
  122. <p>
  123. <strong><?php _e( 'File name', 'acf' ); ?>:</strong>
  124. <a data-name="filename" href="<?php echo esc_url( $o['url'] ); ?>" target="_blank"><?php echo esc_html( $o['filename'] ); ?></a>
  125. </p>
  126. <p>
  127. <strong><?php _e( 'File size', 'acf' ); ?>:</strong>
  128. <span data-name="filesize"><?php echo esc_html( $o['filesize'] ); ?></span>
  129. </p>
  130. </div>
  131. <div class="acf-actions -hover">
  132. <?php if ( $uploader != 'basic' ) : ?>
  133. <a class="acf-icon -pencil dark" data-name="edit" href="#" title="<?php _e( 'Edit', 'acf' ); ?>"></a>
  134. <?php endif; ?>
  135. <a class="acf-icon -cancel dark" data-name="remove" href="#" title="<?php _e( 'Remove', 'acf' ); ?>"></a>
  136. </div>
  137. </div>
  138. <div class="hide-if-value">
  139. <?php if ( $uploader == 'basic' ) : ?>
  140. <?php if ( $field['value'] && ! is_numeric( $field['value'] ) ) : ?>
  141. <div class="acf-error-message"><p><?php echo acf_esc_html( $field['value'] ); ?></p></div>
  142. <?php endif; ?>
  143. <label class="acf-basic-uploader">
  144. <?php
  145. acf_file_input(
  146. array(
  147. 'name' => $field['name'],
  148. 'id' => $field['id'],
  149. )
  150. );
  151. ?>
  152. </label>
  153. <?php else : ?>
  154. <p><?php _e( 'No file selected', 'acf' ); ?> <a data-name="add" class="acf-button button" href="#"><?php _e( 'Add File', 'acf' ); ?></a></p>
  155. <?php endif; ?>
  156. </div>
  157. </div>
  158. <?php
  159. }
  160. /*
  161. * render_field_settings()
  162. *
  163. * Create extra options for your field. This is rendered when editing a field.
  164. * The value of $field['name'] can be used (like bellow) to save extra data to the $field
  165. *
  166. * @type action
  167. * @since 3.6
  168. * @date 23/01/13
  169. *
  170. * @param $field - an array holding all the field's data
  171. */
  172. function render_field_settings( $field ) {
  173. // clear numeric settings
  174. $clear = array(
  175. 'min_size',
  176. 'max_size',
  177. );
  178. foreach ( $clear as $k ) {
  179. if ( empty( $field[ $k ] ) ) {
  180. $field[ $k ] = '';
  181. }
  182. }
  183. // return_format
  184. acf_render_field_setting(
  185. $field,
  186. array(
  187. 'label' => __( 'Return Value', 'acf' ),
  188. 'instructions' => __( 'Specify the returned value on front end', 'acf' ),
  189. 'type' => 'radio',
  190. 'name' => 'return_format',
  191. 'layout' => 'horizontal',
  192. 'choices' => array(
  193. 'array' => __( 'File Array', 'acf' ),
  194. 'url' => __( 'File URL', 'acf' ),
  195. 'id' => __( 'File ID', 'acf' ),
  196. ),
  197. )
  198. );
  199. // library
  200. acf_render_field_setting(
  201. $field,
  202. array(
  203. 'label' => __( 'Library', 'acf' ),
  204. 'instructions' => __( 'Limit the media library choice', 'acf' ),
  205. 'type' => 'radio',
  206. 'name' => 'library',
  207. 'layout' => 'horizontal',
  208. 'choices' => array(
  209. 'all' => __( 'All', 'acf' ),
  210. 'uploadedTo' => __( 'Uploaded to post', 'acf' ),
  211. ),
  212. )
  213. );
  214. // min
  215. acf_render_field_setting(
  216. $field,
  217. array(
  218. 'label' => __( 'Minimum', 'acf' ),
  219. 'instructions' => __( 'Restrict which files can be uploaded', 'acf' ),
  220. 'type' => 'text',
  221. 'name' => 'min_size',
  222. 'prepend' => __( 'File size', 'acf' ),
  223. 'append' => 'MB',
  224. )
  225. );
  226. // max
  227. acf_render_field_setting(
  228. $field,
  229. array(
  230. 'label' => __( 'Maximum', 'acf' ),
  231. 'instructions' => __( 'Restrict which files can be uploaded', 'acf' ),
  232. 'type' => 'text',
  233. 'name' => 'max_size',
  234. 'prepend' => __( 'File size', 'acf' ),
  235. 'append' => 'MB',
  236. )
  237. );
  238. // allowed type
  239. acf_render_field_setting(
  240. $field,
  241. array(
  242. 'label' => __( 'Allowed file types', 'acf' ),
  243. 'instructions' => __( 'Comma separated list. Leave blank for all types', 'acf' ),
  244. 'type' => 'text',
  245. 'name' => 'mime_types',
  246. )
  247. );
  248. }
  249. /*
  250. * format_value()
  251. *
  252. * This filter is appied to the $value after it is loaded from the db and before it is returned to the template
  253. *
  254. * @type filter
  255. * @since 3.6
  256. * @date 23/01/13
  257. *
  258. * @param $value (mixed) the value which was loaded from the database
  259. * @param $post_id (mixed) the $post_id from which the value was loaded
  260. * @param $field (array) the field array holding all the field options
  261. *
  262. * @return $value (mixed) the modified value
  263. */
  264. function format_value( $value, $post_id, $field ) {
  265. // bail early if no value
  266. if ( empty( $value ) ) {
  267. return false;
  268. }
  269. // bail early if not numeric (error message)
  270. if ( ! is_numeric( $value ) ) {
  271. return false;
  272. }
  273. // convert to int
  274. $value = intval( $value );
  275. // format
  276. if ( $field['return_format'] == 'url' ) {
  277. return wp_get_attachment_url( $value );
  278. } elseif ( $field['return_format'] == 'array' ) {
  279. return acf_get_attachment( $value );
  280. }
  281. // return
  282. return $value;
  283. }
  284. /*
  285. * get_media_item_args
  286. *
  287. * description
  288. *
  289. * @type function
  290. * @date 27/01/13
  291. * @since 3.6.0
  292. *
  293. * @param $vars (array)
  294. * @return $vars
  295. */
  296. function get_media_item_args( $vars ) {
  297. $vars['send'] = true;
  298. return( $vars );
  299. }
  300. /*
  301. * update_value()
  302. *
  303. * This filter is appied to the $value before it is updated in the db
  304. *
  305. * @type filter
  306. * @since 3.6
  307. * @date 23/01/13
  308. *
  309. * @param $value - the value which will be saved in the database
  310. * @param $post_id - the $post_id of which the value will be saved
  311. * @param $field - the field array holding all the field options
  312. *
  313. * @return $value - the modified value
  314. */
  315. function update_value( $value, $post_id, $field ) {
  316. // Bail early if no value.
  317. if ( empty( $value ) ) {
  318. return $value;
  319. }
  320. // Parse value for id.
  321. $attachment_id = acf_idval( $value );
  322. // Connect attacment to post.
  323. acf_connect_attachment_to_post( $attachment_id, $post_id );
  324. // Return id.
  325. return $attachment_id;
  326. }
  327. /**
  328. * validate_value
  329. *
  330. * This function will validate a basic file input
  331. *
  332. * @type function
  333. * @date 11/02/2014
  334. * @since 5.0.0
  335. *
  336. * @param $post_id (int)
  337. * @return $post_id (int)
  338. */
  339. function validate_value( $valid, $value, $field, $input ) {
  340. // bail early if empty
  341. if ( empty( $value ) ) {
  342. return $valid;
  343. }
  344. // bail ealry if is numeric
  345. if ( is_numeric( $value ) ) {
  346. return $valid;
  347. }
  348. // bail ealry if not basic string
  349. if ( ! is_string( $value ) ) {
  350. return $valid;
  351. }
  352. // decode value
  353. $file = null;
  354. parse_str( $value, $file );
  355. // bail early if no attachment
  356. if ( empty( $file ) ) {
  357. return $valid;
  358. }
  359. // get errors
  360. $errors = acf_validate_attachment( $file, $field, 'basic_upload' );
  361. // append error
  362. if ( ! empty( $errors ) ) {
  363. $valid = implode( "\n", $errors );
  364. }
  365. // return
  366. return $valid;
  367. }
  368. /**
  369. * Validates file fields updated via the REST API.
  370. *
  371. * @param bool $valid
  372. * @param int $value
  373. * @param array $field
  374. *
  375. * @return bool|WP_Error
  376. */
  377. public function validate_rest_value( $valid, $value, $field ) {
  378. /**
  379. * A bit of a hack, but we use `wp_prepare_attachment_for_js()` here
  380. * since it returns all the data we need to validate the file, and we use this anyways
  381. * to validate fields updated via UI.
  382. */
  383. $attachment = wp_prepare_attachment_for_js( $value );
  384. $param = sprintf( '%s[%s]', $field['prefix'], $field['name'] );
  385. $data = array(
  386. 'param' => $param,
  387. 'value' => (int) $value,
  388. );
  389. if ( ! $attachment ) {
  390. $error = sprintf( __( '%s requires a valid attachment ID.', 'acf' ), $param );
  391. return new WP_Error( 'rest_invalid_param', $error, $data );
  392. }
  393. $errors = acf_validate_attachment( $attachment, $field, 'prepare' );
  394. if ( ! empty( $errors ) ) {
  395. $error = $param . ' - ' . implode( ' ', $errors );
  396. return new WP_Error( 'rest_invalid_param', $error, $data );
  397. }
  398. return $valid;
  399. }
  400. /**
  401. * Return the schema array for the REST API.
  402. *
  403. * @param array $field
  404. * @return array
  405. */
  406. public function get_rest_schema( array $field ) {
  407. $schema = array(
  408. 'type' => array( 'integer', 'null' ),
  409. 'required' => isset( $field['required'] ) && $field['required'],
  410. );
  411. if ( ! empty( $field['min_width'] ) ) {
  412. $schema['minWidth'] = (int) $field['min_width'];
  413. }
  414. if ( ! empty( $field['min_height'] ) ) {
  415. $schema['minHeight'] = (int) $field['min_height'];
  416. }
  417. if ( ! empty( $field['min_size'] ) ) {
  418. $schema['minSize'] = $field['min_size'];
  419. }
  420. if ( ! empty( $field['max_width'] ) ) {
  421. $schema['maxWidth'] = (int) $field['max_width'];
  422. }
  423. if ( ! empty( $field['max_height'] ) ) {
  424. $schema['maxHeight'] = (int) $field['max_height'];
  425. }
  426. if ( ! empty( $field['max_size'] ) ) {
  427. $schema['maxSize'] = $field['max_size'];
  428. }
  429. if ( ! empty( $field['mime_types'] ) ) {
  430. $schema['mimeTypes'] = $field['mime_types'];
  431. }
  432. return $schema;
  433. }
  434. /**
  435. * Apply basic formatting to prepare the value for default REST output.
  436. *
  437. * @param mixed $value
  438. * @param string|int $post_id
  439. * @param array $field
  440. * @return mixed
  441. */
  442. public function format_value_for_rest( $value, $post_id, array $field ) {
  443. return acf_format_numerics( $value );
  444. }
  445. }
  446. // initialize
  447. acf_register_field_type( 'acf_field_file' );
  448. endif; // class_exists check
  449. ?>