PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / 6.9.5
Secure Custom Fields v6.9.5
6.9.5 6.9.4 6.9.3 6.9.2 6.9.1 6.9.0 6.8.9 6.8.7 6.8.8 6.8.6 6.8.4 6.8.5 trunk 6.4.0-beta1 6.4.0-beta2 6.4.1 6.4.1-beta3 6.4.1-beta4 6.4.1-beta5 6.4.1-beta6 6.4.1-beta7 6.4.2 6.5.0 6.5.1 6.5.2 6.5.3 6.5.4 6.5.5 6.5.6 6.5.7 6.6.0 6.7.0 6.7.1 6.8.0 6.8.1 6.8.2 6.8.3
secure-custom-fields / includes / fields / class-acf-field-gallery.php
secure-custom-fields / includes / fields Last commit date
FlexibleContent 3 months ago class-acf-field-accordion.php 3 months ago class-acf-field-button-group.php 3 months ago class-acf-field-checkbox.php 1 month ago class-acf-field-clone.php 3 months ago class-acf-field-color_picker.php 3 months ago class-acf-field-date_picker.php 3 months ago class-acf-field-date_time_picker.php 3 months ago class-acf-field-email.php 3 months ago class-acf-field-file.php 3 months ago class-acf-field-flexible-content.php 1 month ago class-acf-field-gallery.php 4 days ago class-acf-field-google-map.php 3 months ago class-acf-field-group.php 3 months ago class-acf-field-icon_picker.php 8 months ago class-acf-field-image.php 3 months ago class-acf-field-link.php 3 months ago class-acf-field-message.php 1 year ago class-acf-field-nav-menu.php 1 month ago class-acf-field-number.php 3 months ago class-acf-field-oembed.php 1 month ago class-acf-field-output.php 1 year ago class-acf-field-page_link.php 1 week ago class-acf-field-password.php 3 months ago class-acf-field-post_object.php 1 week ago class-acf-field-radio.php 1 month ago class-acf-field-range.php 3 months ago class-acf-field-relationship.php 1 week ago class-acf-field-repeater.php 1 month ago class-acf-field-select.php 2 weeks ago class-acf-field-separator.php 1 year ago class-acf-field-tab.php 1 year ago class-acf-field-taxonomy.php 1 month ago class-acf-field-text.php 1 month ago class-acf-field-textarea.php 1 month ago class-acf-field-time_picker.php 3 months ago class-acf-field-true_false.php 3 months ago class-acf-field-url.php 1 month ago class-acf-field-user.php 2 weeks ago class-acf-field-wysiwyg.php 3 months ago class-acf-field.php 3 months ago class-acf-repeater-table.php 1 year ago index.php 1 year ago
class-acf-field-gallery.php
995 lines
1 <?php
2 /**
3 * The Gallery Field.
4 *
5 * @package wordpress/secure-custom-fields
6 */
7
8 // phpcs:disable PEAR.NamingConventions.ValidClassName
9
10 if ( ! class_exists( 'acf_field_gallery' ) ) :
11
12 /**
13 * The Field Gallery class.
14 */
15 class acf_field_gallery extends acf_field {
16 /**
17 * This function will setup the field type data
18 *
19 * @type function
20 * @date 5/03/2014
21 * @since ACF 5.0.0
22 *
23 * @return void
24 */
25 public function initialize() {
26
27 // vars
28 $this->name = 'gallery';
29 $this->label = __( 'Gallery', 'secure-custom-fields' );
30 $this->category = 'content';
31 $this->description = __( 'An interactive interface for managing a collection of attachments, such as images.', 'secure-custom-fields' );
32 $this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-gallery.png';
33 $this->doc_url = 'https://developer.wordpress.org/secure-custom-fields/features/fields/gallery/';
34 $this->tutorial_url = 'https://developer.wordpress.org/secure-custom-fields/features/fields/gallery/gallery-tutorial/';
35 $this->pro = true;
36 $this->supports = array( 'bindings' => false );
37 $this->defaults = array(
38 'return_format' => 'array',
39 'preview_size' => 'medium',
40 'insert' => 'append',
41 'library' => 'all',
42 'min' => 0,
43 'max' => 0,
44 'min_width' => 0,
45 'min_height' => 0,
46 'min_size' => 0,
47 'max_width' => 0,
48 'max_height' => 0,
49 'max_size' => 0,
50 'mime_types' => '',
51 );
52
53 // actions
54 add_action( 'wp_ajax_acf/fields/gallery/get_attachment', array( $this, 'ajax_get_attachment' ) );
55 add_action( 'wp_ajax_nopriv_acf/fields/gallery/get_attachment', array( $this, 'ajax_get_attachment' ) );
56
57 add_action( 'wp_ajax_acf/fields/gallery/update_attachment', array( $this, 'ajax_update_attachment' ) );
58 add_action( 'wp_ajax_nopriv_acf/fields/gallery/update_attachment', array( $this, 'ajax_update_attachment' ) );
59
60 add_action( 'wp_ajax_acf/fields/gallery/get_sort_order', array( $this, 'ajax_get_sort_order' ) );
61 add_action( 'wp_ajax_nopriv_acf/fields/gallery/get_sort_order', array( $this, 'ajax_get_sort_order' ) );
62 }
63
64 /**
65 * Enqueue admin scripts.
66 *
67 * @type function
68 * @date 16/12/2015
69 * @since ACF 5.3.2
70 */
71 public function input_admin_enqueue_scripts() {
72
73 // localize
74 acf_localize_text(
75 array(
76 'Add Image to Gallery' => __( 'Add Image to Gallery', 'secure-custom-fields' ),
77 'Maximum selection reached' => __( 'Maximum selection reached', 'secure-custom-fields' ),
78 )
79 );
80 }
81
82 /**
83 * AJAX handler for retrieving and rendering an attachment.
84 *
85 * @since ACF 5.0.0
86 *
87 * @return void
88 */
89 public function ajax_get_attachment() {
90 // Get args.
91 $args = acf_request_args(
92 array(
93 'id' => 0,
94 'field_key' => '',
95 'nonce' => '',
96 )
97 );
98
99 // Validate request.
100 if ( ! acf_verify_ajax( $args['nonce'], $args['field_key'], true, 'gallery' ) ) {
101 die();
102 }
103
104 // Cast args.
105 $args['id'] = (int) $args['id'];
106
107 // Bail early if no id.
108 if ( ! $args['id'] ) {
109 die();
110 }
111
112 // Load field.
113 $field = acf_get_field( $args['field_key'] );
114 if ( ! $field ) {
115 die();
116 }
117
118 // Load attachment.
119 $attachment = get_post( $args['id'] );
120 if ( ! $attachment || 'attachment' !== $attachment->post_type ) {
121 wp_die();
122 }
123
124 // Inherited attachments use their parent for visibility when available.
125 $visibility_post = $attachment;
126 if ( 'inherit' === $attachment->post_status && $attachment->post_parent > 0 ) {
127 $parent = get_post( $attachment->post_parent );
128 if ( $parent ) {
129 $visibility_post = $parent;
130 }
131 }
132
133 // Confirm the attachment or its visibility post can be read.
134 if (
135 ! is_post_publicly_viewable( $visibility_post ) &&
136 ! current_user_can( 'read_post', $attachment->ID ) &&
137 ( $attachment->ID === $visibility_post->ID || ! current_user_can( 'read_post', $visibility_post->ID ) )
138 ) {
139 wp_die();
140 }
141
142 // Render.
143 $this->render_attachment( $args['id'], $field );
144 wp_die();
145 }
146
147 /**
148 * AJAX handler for updating an attachment.
149 *
150 * @since ACF 5.0.0
151 *
152 * @return void
153 */
154 public function ajax_update_attachment() {
155 $args = acf_request_args(
156 array(
157 'nonce' => '',
158 'field_key' => '',
159 )
160 );
161
162 if ( ! acf_verify_ajax( $args['nonce'], $args['field_key'], true, 'gallery' ) ) {
163 wp_send_json_error();
164 }
165
166 // bail early if no attachments
167 if ( empty( $_POST['attachments'] ) ) {
168 wp_send_json_error();
169 }
170
171 // loop over attachments
172 foreach ( wp_unslash( $_POST['attachments'] ) as $id => $changes ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized by WP core when saved.
173 $id = (int) $id;
174
175 if ( ! current_user_can( 'edit_post', $id ) ) {
176 wp_send_json_error();
177 }
178
179 $post = get_post( $id, ARRAY_A );
180
181 if ( 'attachment' !== $post['post_type'] ) {
182 wp_send_json_error();
183 }
184
185 if ( isset( $changes['title'] ) ) {
186 $post['post_title'] = $changes['title'];
187 }
188
189 if ( isset( $changes['caption'] ) ) {
190 $post['post_excerpt'] = $changes['caption'];
191 }
192
193 if ( isset( $changes['description'] ) ) {
194 $post['post_content'] = $changes['description'];
195 }
196
197 if ( isset( $changes['alt'] ) ) {
198 $alt = wp_unslash( $changes['alt'] );
199 if ( get_post_meta( $id, '_wp_attachment_image_alt', true ) !== $alt ) {
200 $alt = wp_strip_all_tags( $alt, true );
201 update_post_meta( $id, '_wp_attachment_image_alt', wp_slash( $alt ) );
202 }
203 }
204
205 // save post
206 wp_update_post( $post );
207
208 /** This filter is documented in wp-admin/includes/media.php */
209 // - seems off to run this filter AFTER the update_post function, but there is a reason
210 // - when placed BEFORE, an empty post_title will be populated by WP
211 // - this filter will still allow 3rd party to save extra image data!
212 $post = apply_filters( 'attachment_fields_to_save', $post, $changes );
213
214 // save meta
215 acf_save_post( $id );
216 }
217
218 // return
219 wp_send_json_success();
220 }
221
222 /**
223 * AJAX handler for getting the attachment sort order.
224 *
225 * @since ACF 5.0.0
226 *
227 * @return void
228 */
229 public function ajax_get_sort_order() {
230 $order = 'DESC';
231 $args = acf_parse_args(
232 $_POST, // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verified below.
233 array(
234 'ids' => 0,
235 'sort' => 'date',
236 'field_key' => '',
237 'nonce' => '',
238 )
239 );
240
241 if ( ! acf_verify_ajax( $args['nonce'], $args['field_key'], true, 'gallery' ) ) {
242 wp_send_json_error();
243 }
244
245 // Reverse order.
246 if ( 'reverse' === $args['sort'] ) {
247 $ids = array_reverse( $args['ids'] );
248 wp_send_json_success( $ids );
249 }
250
251 // Ascending order.
252 if ( 'title' === $args['sort'] ) {
253 $order = 'ASC';
254 }
255
256 // Find attachments (DISTINCT POSTS).
257 $ids = get_posts(
258 array(
259 'post_type' => 'attachment',
260 'numberposts' => -1,
261 'post_status' => 'any',
262 'post__in' => $args['ids'],
263 'order' => $order,
264 'orderby' => $args['sort'],
265 'fields' => 'ids',
266 )
267 );
268
269 if ( ! empty( $ids ) ) {
270 wp_send_json_success( $ids );
271 }
272
273 wp_send_json_error();
274 }
275
276 /**
277 * Renders the sidebar HTML shown when selecting an attachment.
278 *
279 * @date 13/12/2013
280 * @since ACF 5.0.0
281 *
282 * @param integer $id The attachment ID.
283 * @param array $field The field array.
284 * @return void
285 */
286 public function render_attachment( $id, $field ) {
287 // Load attachment data.
288 $attachment = wp_prepare_attachment_for_js( $id );
289 $compat = get_compat_media_markup( $id );
290
291 // Get attachment thumbnail (video).
292 if ( isset( $attachment['thumb']['src'] ) ) {
293 $thumb = $attachment['thumb']['src'];
294
295 // Look for thumbnail size (image).
296 } elseif ( isset( $attachment['sizes']['thumbnail']['url'] ) ) {
297 $thumb = $attachment['sizes']['thumbnail']['url'];
298
299 // Use url for svg.
300 } elseif ( 'image' === $attachment['type'] ) {
301 $thumb = $attachment['url'];
302
303 // Default to icon.
304 } else {
305 $thumb = wp_mime_type_icon( $id );
306 }
307
308 // Get attachment dimensions / time / size.
309 $dimensions = '';
310 if ( 'audio' === $attachment['type'] ) {
311 $dimensions = __( 'Length', 'secure-custom-fields' ) . ': ' . $attachment['fileLength'];
312 } elseif ( ! empty( $attachment['width'] ) ) {
313 $dimensions = $attachment['width'] . ' x ' . $attachment['height'];
314 }
315 if ( ! empty( $attachment['filesizeHumanReadable'] ) ) {
316 $dimensions .= ' (' . $attachment['filesizeHumanReadable'] . ')';
317 }
318
319 ?>
320 <div class="acf-gallery-side-info">
321 <img src="<?php echo esc_url( $thumb ); ?>" alt="<?php echo esc_attr( $attachment['alt'] ); ?>" />
322 <p class="filename"><strong><?php echo esc_html( $attachment['filename'] ); ?></strong></p>
323 <p class="uploaded"><?php echo esc_html( $attachment['dateFormatted'] ); ?></p>
324 <p class="dimensions"><?php echo esc_html( $dimensions ); ?></p>
325 <p class="actions">
326 <a href="#" class="acf-gallery-edit" data-id="<?php echo esc_attr( $id ); ?>"><?php esc_html_e( 'Edit', 'secure-custom-fields' ); ?></a>
327 <a href="#" class="acf-gallery-remove" data-id="<?php echo esc_attr( $id ); ?>"><?php esc_html_e( 'Remove', 'secure-custom-fields' ); ?></a>
328 </p>
329 </div>
330 <table class="form-table">
331 <tbody>
332 <?php
333
334 // Render fields.
335 $prefix = 'attachments[' . $id . ']';
336
337 acf_render_field_wrap(
338 array(
339 'name' => 'title',
340 'prefix' => $prefix,
341 'type' => 'text',
342 'label' => __( 'Title', 'secure-custom-fields' ),
343 'value' => $attachment['title'],
344 ),
345 'tr'
346 );
347
348 acf_render_field_wrap(
349 array(
350 'name' => 'caption',
351 'prefix' => $prefix,
352 'type' => 'textarea',
353 'label' => __( 'Caption', 'secure-custom-fields' ),
354 'value' => $attachment['caption'],
355 ),
356 'tr'
357 );
358
359 acf_render_field_wrap(
360 array(
361 'name' => 'alt',
362 'prefix' => $prefix,
363 'type' => 'text',
364 'label' => __( 'Alt Text', 'secure-custom-fields' ),
365 'value' => $attachment['alt'],
366 ),
367 'tr'
368 );
369
370 acf_render_field_wrap(
371 array(
372 'name' => 'description',
373 'prefix' => $prefix,
374 'type' => 'textarea',
375 'label' => __( 'Description', 'secure-custom-fields' ),
376 'value' => $attachment['description'],
377 ),
378 'tr'
379 );
380
381 ?>
382 </tbody>
383 </table>
384 <?php
385
386 // Display compat fields.
387 echo $compat['item']; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped inside get_compat_media_markup().
388 }
389
390 /**
391 * Creates the HTML interface for the gallery field.
392 *
393 * @param array $field The field array holding all the field's data.
394 *
395 * @type action
396 * @since ACF 3.6
397 * @date 23/01/13
398 * @return void
399 */
400 public function render_field( $field ) {
401
402 // Enqueue uploader assets.
403 acf_enqueue_uploader();
404
405 // Control attributes.
406 $attrs = array(
407 'id' => $field['id'],
408 'class' => "acf-gallery {$field['class']}",
409 'data-library' => $field['library'],
410 'data-preview_size' => $field['preview_size'],
411 'data-min' => $field['min'],
412 'data-max' => $field['max'],
413 'data-mime_types' => $field['mime_types'],
414 'data-insert' => $field['insert'],
415 'data-columns' => 4,
416 'data-nonce' => wp_create_nonce( 'acf_field_' . $this->name . '_' . $field['key'] ),
417 );
418
419 // Set gallery height with default of 400px and minimum of 200px.
420 $height = acf_get_user_setting( 'gallery_height', 400 );
421 $height = max( $height, 200 );
422 $attrs['style'] = "height:{$height}px";
423
424 // Load attachments.
425 $attachments = array();
426 if ( $field['value'] ) {
427
428 // Clean value into an array of IDs.
429 $attachment_ids = array_map( 'intval', acf_array( $field['value'] ) );
430
431 // Find posts in database (ensures all results are real).
432 $posts = acf_get_posts(
433 array(
434 'post_type' => 'attachment',
435 'post__in' => $attachment_ids,
436 'update_post_meta_cache' => true,
437 'update_post_term_cache' => false,
438 )
439 );
440
441 // Load attachment data for each post.
442 $attachments = array_map( 'acf_get_attachment', $posts );
443 }
444
445 ?>
446 <div <?php echo acf_esc_attrs( $attrs ); ?>>
447 <input type="hidden" name="<?php echo esc_attr( $field['name'] ); ?>" value="" />
448 <div class="acf-gallery-main">
449 <div class="acf-gallery-attachments">
450 <?php if ( $attachments ) : ?>
451 <?php
452 foreach ( $attachments as $i => $attachment ) :
453
454 // Vars
455 $a_id = $attachment['ID'];
456 $a_title = $attachment['title'];
457 $a_type = $attachment['type'];
458 $a_filename = $attachment['filename'];
459 $a_class = "acf-gallery-attachment -{$a_type}";
460
461 // Get thumbnail.
462 $a_thumbnail = acf_get_post_thumbnail( $a_id, $field['preview_size'] );
463 $a_class .= ( 'icon' === $a_thumbnail['type'] ) ? ' -icon' : '';
464
465 ?>
466 <div class="<?php echo esc_attr( $a_class ); ?>" data-id="<?php echo esc_attr( $a_id ); ?>">
467 <input type="hidden" name="<?php echo esc_attr( $field['name'] ); ?>[]" value="<?php echo esc_attr( $a_id ); ?>" />
468 <div class="margin">
469 <div class="thumbnail">
470 <img src="<?php echo esc_url( $a_thumbnail['url'] ); ?>" alt="" />
471 </div>
472 <?php if ( 'image' !== $a_type ) : ?>
473 <div class="filename"><?php echo acf_esc_html( acf_get_truncated( $a_filename, 30 ) ); ?></div>
474 <?php endif; ?>
475 </div>
476 <div class="actions">
477 <a class="acf-icon -cancel dark acf-gallery-remove" href="#" data-id="<?php echo esc_attr( $a_id ); ?>" title="<?php esc_html_e( 'Remove', 'secure-custom-fields' ); ?>"></a>
478 </div>
479 </div>
480 <?php endforeach; ?>
481 <?php endif; ?>
482 </div>
483 <div class="acf-gallery-toolbar">
484 <ul class="acf-hl">
485 <li>
486 <a href="#" class="acf-button button button-primary acf-gallery-add"><?php esc_html_e( 'Add to gallery', 'secure-custom-fields' ); ?></a>
487 </li>
488 <li class="acf-fr">
489 <select class="acf-gallery-sort">
490 <option value=""><?php esc_html_e( 'Bulk actions', 'secure-custom-fields' ); ?></option>
491 <option value="date"><?php esc_html_e( 'Sort by date uploaded', 'secure-custom-fields' ); ?></option>
492 <option value="modified"><?php esc_html_e( 'Sort by date modified', 'secure-custom-fields' ); ?></option>
493 <option value="title"><?php esc_html_e( 'Sort by title', 'secure-custom-fields' ); ?></option>
494 <option value="reverse"><?php esc_html_e( 'Reverse current order', 'secure-custom-fields' ); ?></option>
495 </select>
496 </li>
497 </ul>
498 </div>
499 </div>
500 <div class="acf-gallery-side">
501 <div class="acf-gallery-side-inner">
502 <div class="acf-gallery-side-data"></div>
503 <div class="acf-gallery-toolbar">
504 <ul class="acf-hl">
505 <li>
506 <a href="#" class="acf-button button acf-gallery-close"><?php esc_html_e( 'Close', 'secure-custom-fields' ); ?></a>
507 </li>
508 <li class="acf-fr">
509 <a class="acf-button button button-primary acf-gallery-update" href="#"><?php esc_html_e( 'Update', 'secure-custom-fields' ); ?></a>
510 </li>
511 </ul>
512 </div>
513 </div>
514 </div>
515 </div>
516 <?php
517 }
518
519
520 /**
521 * Create extra options for your field. This is rendered when editing a field.
522 * The value of $field['name'] can be used (like bellow) to save extra data to the $field
523 *
524 * @type action
525 * @since ACF 3.6
526 * @date 23/01/13
527 *
528 * @param array $field an array holding all the field's data.
529 */
530 public function render_field_settings( $field ) {
531 acf_render_field_setting(
532 $field,
533 array(
534 'label' => __( 'Return Format', 'secure-custom-fields' ),
535 'instructions' => '',
536 'type' => 'radio',
537 'name' => 'return_format',
538 'layout' => 'horizontal',
539 'choices' => array(
540 'array' => __( 'Image Array', 'secure-custom-fields' ),
541 'url' => __( 'Image URL', 'secure-custom-fields' ),
542 'id' => __( 'Image ID', 'secure-custom-fields' ),
543 ),
544 )
545 );
546
547 acf_render_field_setting(
548 $field,
549 array(
550 'label' => __( 'Library', 'secure-custom-fields' ),
551 'instructions' => __( 'Limit the media library choice', 'secure-custom-fields' ),
552 'type' => 'radio',
553 'name' => 'library',
554 'layout' => 'horizontal',
555 'choices' => array(
556 'all' => __( 'All', 'secure-custom-fields' ),
557 'uploadedTo' => __( 'Uploaded to post', 'secure-custom-fields' ),
558 ),
559 )
560 );
561 }
562
563 /**
564 * Renders the field settings used in the "Validation" tab.
565 *
566 * @since ACF 6.0
567 *
568 * @param array $field The field settings array.
569 * @return void
570 */
571 public function render_field_validation_settings( $field ) {
572 // Clear numeric settings.
573 $clear = array(
574 'min',
575 'max',
576 'min_width',
577 'min_height',
578 'min_size',
579 'max_width',
580 'max_height',
581 'max_size',
582 );
583
584 foreach ( $clear as $k ) {
585 if ( empty( $field[ $k ] ) ) {
586 $field[ $k ] = '';
587 }
588 }
589
590 acf_render_field_setting(
591 $field,
592 array(
593 'label' => __( 'Minimum Selection', 'secure-custom-fields' ),
594 'instructions' => '',
595 'type' => 'number',
596 'name' => 'min',
597 )
598 );
599
600 acf_render_field_setting(
601 $field,
602 array(
603 'label' => __( 'Maximum Selection', 'secure-custom-fields' ),
604 'instructions' => '',
605 'type' => 'number',
606 'name' => 'max',
607 )
608 );
609
610 acf_render_field_setting(
611 $field,
612 array(
613 'label' => __( 'Minimum', 'secure-custom-fields' ),
614 'hint' => __( 'Restrict which images can be uploaded', 'secure-custom-fields' ),
615 'type' => 'text',
616 'name' => 'min_width',
617 'prepend' => __( 'Width', 'secure-custom-fields' ),
618 'append' => 'px',
619 )
620 );
621
622 acf_render_field_setting(
623 $field,
624 array(
625 'label' => '',
626 'type' => 'text',
627 'name' => 'min_height',
628 'prepend' => __( 'Height', 'secure-custom-fields' ),
629 'append' => 'px',
630 '_append' => 'min_width',
631 )
632 );
633
634 acf_render_field_setting(
635 $field,
636 array(
637 'label' => '',
638 'type' => 'text',
639 'name' => 'min_size',
640 'prepend' => __( 'File size', 'secure-custom-fields' ),
641 'append' => 'MB',
642 '_append' => 'min_width',
643 )
644 );
645
646 acf_render_field_setting(
647 $field,
648 array(
649 'label' => __( 'Maximum', 'secure-custom-fields' ),
650 'hint' => __( 'Restrict which images can be uploaded', 'secure-custom-fields' ),
651 'type' => 'text',
652 'name' => 'max_width',
653 'prepend' => __( 'Width', 'secure-custom-fields' ),
654 'append' => 'px',
655 )
656 );
657
658 acf_render_field_setting(
659 $field,
660 array(
661 'label' => '',
662 'type' => 'text',
663 'name' => 'max_height',
664 'prepend' => __( 'Height', 'secure-custom-fields' ),
665 'append' => 'px',
666 '_append' => 'max_width',
667 )
668 );
669
670 acf_render_field_setting(
671 $field,
672 array(
673 'label' => '',
674 'type' => 'text',
675 'name' => 'max_size',
676 'prepend' => __( 'File size', 'secure-custom-fields' ),
677 'append' => 'MB',
678 '_append' => 'max_width',
679 )
680 );
681
682 acf_render_field_setting(
683 $field,
684 array(
685 'label' => __( 'Allowed File Types', 'secure-custom-fields' ),
686 'hint' => __( 'Comma separated list. Leave blank for all types', 'secure-custom-fields' ),
687 'type' => 'text',
688 'name' => 'mime_types',
689 )
690 );
691 }
692
693 /**
694 * Renders the field settings used in the "Presentation" tab.
695 *
696 * @since ACF 6.0
697 *
698 * @param array $field The field settings array.
699 * @return void
700 */
701 public function render_field_presentation_settings( $field ) {
702 acf_render_field_setting(
703 $field,
704 array(
705 'label' => __( 'Insert', 'secure-custom-fields' ),
706 'instructions' => __( 'Specify where new attachments are added', 'secure-custom-fields' ),
707 'type' => 'select',
708 'name' => 'insert',
709 'choices' => array(
710 'append' => __( 'Append to the end', 'secure-custom-fields' ),
711 'prepend' => __( 'Prepend to the beginning', 'secure-custom-fields' ),
712 ),
713 )
714 );
715
716 acf_render_field_setting(
717 $field,
718 array(
719 'label' => __( 'Preview Size', 'secure-custom-fields' ),
720 'instructions' => '',
721 'type' => 'select',
722 'name' => 'preview_size',
723 'choices' => acf_get_image_sizes(),
724 )
725 );
726 }
727
728 /**
729 * Filters the value after it is loaded from the database and before it is returned to the template.
730 *
731 * @type filter
732 * @since ACF 3.6
733 * @date 23/01/13
734 *
735 * @param mixed $value The value which was loaded from the database.
736 * @param mixed $post_id The post ID from which the value was loaded.
737 * @param array $field The field array holding all the field options.
738 *
739 * @return mixed The modified value.
740 */
741 public function format_value( $value, $post_id, $field ) {
742
743 // Bail early if no value.
744 if ( ! $value ) {
745 return false;
746 }
747
748 // Clean value into an array of IDs.
749 $attachment_ids = array_map( 'intval', acf_array( $value ) );
750
751 // Find posts in database (ensures all results are real).
752 $posts = acf_get_posts(
753 array(
754 'post_type' => 'attachment',
755 'post__in' => $attachment_ids,
756 'update_post_meta_cache' => true,
757 'update_post_term_cache' => false,
758 )
759 );
760
761 // Bail early if no posts found.
762 if ( ! $posts ) {
763 return false;
764 }
765
766 // Format values using field settings.
767 $value = array();
768 foreach ( $posts as $post ) {
769 switch ( $field['return_format'] ) {
770 case 'object':
771 $item = $post;
772 break;
773 case 'array':
774 $item = acf_get_attachment( $post );
775 break;
776 case 'url':
777 $item = wp_get_attachment_url( $post->ID );
778 break;
779 default:
780 $item = $post->ID;
781 }
782
783 // Append item.
784 $value[] = $item;
785 }
786
787 // Return.
788 return $value;
789 }
790
791
792 /**
793 * Validates the value for this field.
794 *
795 * @type function
796 * @date 11/02/2014
797 * @since ACF 5.0.0
798 *
799 * @param bool $valid Whether the value is valid.
800 * @param mixed $value The field value.
801 * @param array $field The field array.
802 * @param string $input The input element's name attribute.
803 * @return bool|string True if valid, error message if not.
804 */
805 public function validate_value( $valid, $value, $field, $input ) {
806
807 if ( empty( $value ) || ! is_array( $value ) ) {
808 $value = array();
809 }
810
811 if ( count( $value ) < $field['min'] ) {
812 /* translators: 1: field label, 2: minimum number of selections */
813 $valid = _n( '%1$s requires at least %2$s selection', '%1$s requires at least %2$s selections', $field['min'], 'secure-custom-fields' );
814 $valid = sprintf( $valid, $field['label'], $field['min'] );
815 }
816
817 return $valid;
818 }
819
820
821 /**
822 * This filter is applied to the $value before it is updated in the db
823 *
824 * @type filter
825 * @since ACF 3.6
826 * @date 23/01/13
827 *
828 * @param mixed $value The value which will be saved in the database.
829 * @param mixed $post_id The post_id of which the value will be saved.
830 * @param array $field The field array holding all the field options.
831 *
832 * @return $value - the modified value
833 */
834 public function update_value( $value, $post_id, $field ) {
835
836 // Bail early if no value.
837 if ( empty( $value ) ) {
838 return $value;
839 }
840
841 // Convert to array.
842 $value = acf_array( $value );
843
844 // Format array of values.
845 // - ensure each value is an id.
846 // - Parse each id as string for SQL LIKE queries.
847 $value = array_map( 'acf_idval', $value );
848 $value = array_map( 'strval', $value );
849
850 // Return value.
851 return $value;
852 }
853
854 /**
855 * Validates file fields updated via the REST API.
856 *
857 * @param boolean $valid The current validity boolean.
858 * @param integer $value The value of the field.
859 * @param array $field The field array.
860 * @return boolean|WP
861 */
862 public function validate_rest_value( $valid, $value, $field ) {
863 if ( ! $valid || ! is_array( $value ) ) {
864 return $valid;
865 }
866
867 foreach ( $value as $attachment_id ) {
868 $file_valid = acf_get_field_type( 'file' )->validate_rest_value( $valid, $attachment_id, $field );
869
870 if ( is_wp_error( $file_valid ) ) {
871 return $file_valid;
872 }
873 }
874
875 return $valid;
876 }
877
878 /**
879 * Return the schema array for the REST API.
880 *
881 * @param array $field The field array.
882 * @return array
883 */
884 public function get_rest_schema( array $field ) {
885 $schema = array(
886 'type' => array( 'array', 'null' ),
887 'required' => ! empty( $field['required'] ),
888 'items' => array(
889 'type' => 'number',
890 ),
891 );
892
893 if ( ! empty( $field['min'] ) ) {
894 $schema['minItems'] = (int) $field['min'];
895 }
896
897 if ( ! empty( $field['max'] ) ) {
898 $schema['maxItems'] = (int) $field['max'];
899 }
900
901 return $schema;
902 }
903
904 /**
905 * Returns an array of links for this field's value.
906 *
907 * @see \acf_field::get_rest_links()
908 * @param mixed $value The raw (unformatted) field value.
909 * @param integer|string $post_id The post ID.
910 * @param array $field The field array.
911 * @return array
912 */
913 public function get_rest_links( $value, $post_id, array $field ) {
914 $links = array();
915
916 if ( empty( $value ) ) {
917 return $links;
918 }
919
920 foreach ( (array) $value as $object_id ) {
921 $links[] = array(
922 'rel' => 'acf:attachment',
923 'href' => rest_url( '/wp/v2/media/' . $object_id ),
924 'embeddable' => true,
925 );
926 }
927
928 return $links;
929 }
930
931 /**
932 * Apply basic formatting to prepare the value for default REST output.
933 *
934 * @param mixed $value The field value.
935 * @param string|integer $post_id The post ID.
936 * @param array $field The field array.
937 * @return mixed
938 */
939 public function format_value_for_rest( $value, $post_id, array $field ) {
940 return acf_format_numerics( $value );
941 }
942
943 /**
944 * Formats the field value for JSON-LD output.
945 *
946 * @since 6.8.0
947 *
948 * @param mixed $value The value of the field.
949 * @param integer|string $post_id The ID of the post.
950 * @param array $field The field array.
951 * @return mixed
952 */
953 public function format_value_for_jsonld( $value, $post_id, $field ) {
954 if ( empty( $value ) || ! is_array( $value ) ) {
955 return null;
956 }
957
958 $image_field_type = acf_get_field_type( 'image' );
959 $images = array();
960
961 foreach ( $value as $attachment_id ) {
962 // Create a temporary field config with the same output format.
963 $image_field = array(
964 'schema_output_format' => $field['schema_output_format'] ?? '',
965 'schema_property' => $field['schema_property'] ?? '',
966 );
967
968 $formatted = $image_field_type->format_value_for_jsonld( $attachment_id, $post_id, $image_field );
969 if ( $formatted ) {
970 $images[] = $formatted;
971 }
972 }
973
974 return empty( $images ) ? null : $images;
975 }
976
977 /**
978 * Returns an array of JSON-LD Property output types that are supported by this field type.
979 *
980 * @since 6.8
981 *
982 * @return string[]
983 */
984 public function get_jsonld_output_types(): array {
985 return array( 'ImageObject', 'URL' );
986 }
987 }
988
989
990 // initialize
991 acf_register_field_type( 'acf_field_gallery' );
992 endif; // class_exists check
993
994 ?>
995