PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / 6.4.0-beta2
Secure Custom Fields v6.4.0-beta2
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-page_link.php
secure-custom-fields / includes / fields Last commit date
class-acf-field-accordion.php 1 year ago class-acf-field-button-group.php 1 year ago class-acf-field-checkbox.php 1 year ago class-acf-field-color_picker.php 1 year ago class-acf-field-date_picker.php 1 year ago class-acf-field-date_time_picker.php 1 year ago class-acf-field-email.php 1 year ago class-acf-field-file.php 1 year ago class-acf-field-google-map.php 1 year ago class-acf-field-group.php 1 year ago class-acf-field-icon_picker.php 1 year ago class-acf-field-image.php 1 year ago class-acf-field-link.php 1 year ago class-acf-field-message.php 1 year ago class-acf-field-number.php 1 year ago class-acf-field-oembed.php 1 year ago class-acf-field-output.php 1 year ago class-acf-field-page_link.php 1 year ago class-acf-field-password.php 1 year ago class-acf-field-post_object.php 1 year ago class-acf-field-radio.php 1 year ago class-acf-field-range.php 1 year ago class-acf-field-relationship.php 1 year ago class-acf-field-select.php 1 year ago class-acf-field-separator.php 1 year ago class-acf-field-tab.php 1 year ago class-acf-field-taxonomy.php 1 year ago class-acf-field-text.php 1 year ago class-acf-field-textarea.php 1 year ago class-acf-field-time_picker.php 1 year ago class-acf-field-true_false.php 1 year ago class-acf-field-url.php 1 year ago class-acf-field-user.php 1 year ago class-acf-field-wysiwyg.php 1 year ago class-acf-field.php 1 year ago index.php 1 year ago
class-acf-field-page_link.php
706 lines
1 <?php
2
3 if ( ! class_exists( 'acf_field_page_link' ) ) :
4
5 class acf_field_page_link extends acf_field {
6
7
8 /**
9 * This function will setup the field type data
10 *
11 * @type function
12 * @date 5/03/2014
13 * @since 5.0.0
14 *
15 * @param n/a
16 * @return n/a
17 */
18 function initialize() {
19
20 // vars
21 $this->name = 'page_link';
22 $this->label = __( 'Page Link', 'acf' );
23 $this->category = 'relational';
24 $this->description = __( 'An interactive dropdown to select one or more posts, pages, custom post type items or archive URLs, with the option to search.', 'acf' );
25 $this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-page-link.png';
26 $this->doc_url = 'https://www.advancedcustomfields.com/resources/page-link/';
27 $this->defaults = array(
28 'post_type' => array(),
29 'taxonomy' => array(),
30 'allow_null' => 0,
31 'multiple' => 0,
32 'allow_archives' => 1,
33 );
34
35 // extra
36 add_action( 'wp_ajax_acf/fields/page_link/query', array( $this, 'ajax_query' ) );
37 add_action( 'wp_ajax_nopriv_acf/fields/page_link/query', array( $this, 'ajax_query' ) );
38 add_filter( 'acf/conditional_logic/choices', array( $this, 'render_field_page_link_conditional_choices' ), 10, 3 );
39 }
40
41 /**
42 * Filters choices in page link conditions.
43 *
44 * @since 6.3
45 *
46 * @param array $choices The selected choice.
47 * @param array $conditional_field The conditional field settings object.
48 * @param string $rule_value The rule value.
49 * @return array
50 */
51 public function render_field_page_link_conditional_choices( $choices, $conditional_field, $rule_value ) {
52 if ( ! is_array( $conditional_field ) || $conditional_field['type'] !== 'page_link' ) {
53 return $choices;
54 }
55 if ( ! empty( $rule_value ) ) {
56 $post_title = get_the_title( $rule_value );
57 $choices = array( $rule_value => $post_title );
58 }
59 return $choices;
60 }
61
62 /**
63 * Returns AJAX results for the Page Link field.
64 *
65 * @since 5.0.0
66 *
67 * @return void
68 */
69 public function ajax_query() {
70 $nonce = acf_request_arg( 'nonce', '' );
71 $key = acf_request_arg( 'field_key', '' );
72 $conditional_logic = (bool) acf_request_arg( 'conditional_logic', false );
73
74 if ( $conditional_logic ) {
75 if ( ! acf_current_user_can_admin() ) {
76 die();
77 }
78
79 // Use the standard ACF admin nonce.
80 $nonce = '';
81 $key = '';
82 }
83
84 if ( ! acf_verify_ajax( $nonce, $key ) ) {
85 die();
86 }
87
88 // defaults
89 $options = acf_parse_args(
90 $_POST,
91 array(
92 'post_id' => 0,
93 's' => '',
94 'field_key' => '',
95 'paged' => 1,
96 'include' => '',
97 )
98 );
99
100 // vars
101 $results = array();
102 $args = array();
103 $s = false;
104 $is_search = false;
105
106 // paged
107 $args['posts_per_page'] = 20;
108 $args['paged'] = $options['paged'];
109
110 // search
111 if ( $options['s'] !== '' ) {
112
113 // strip slashes (search may be integer)
114 $s = wp_unslash( strval( $options['s'] ) );
115
116 // update vars
117 $args['s'] = $s;
118 $is_search = true;
119 }
120
121 // load field
122 $field = acf_get_field( $options['field_key'] );
123 if ( ! $field ) {
124 die();
125 }
126
127 // update $args
128 if ( ! empty( $field['post_type'] ) ) {
129 $args['post_type'] = acf_get_array( $field['post_type'] );
130 } else {
131 $args['post_type'] = acf_get_post_types();
132 }
133
134 // post status
135 if ( ! empty( $options['post_status'] ) ) {
136 $args['post_status'] = acf_get_array( $options['post_status'] );
137 } elseif ( ! empty( $field['post_status'] ) ) {
138 $args['post_status'] = acf_get_array( $field['post_status'] );
139 }
140
141 // create tax queries
142 if ( ! empty( $field['taxonomy'] ) ) {
143
144 // append to $args
145 $args['tax_query'] = array();
146
147 // decode terms
148 $taxonomies = acf_decode_taxonomy_terms( $field['taxonomy'] );
149
150 // now create the tax queries
151 foreach ( $taxonomies as $taxonomy => $terms ) {
152 $args['tax_query'][] = array(
153 'taxonomy' => $taxonomy,
154 'field' => 'slug',
155 'terms' => $terms,
156 );
157 }
158 }
159
160 if ( ! empty( $options['include'] ) ) {
161 $args['include'] = $options['include'];
162 }
163
164 // filters
165 $args = apply_filters( 'acf/fields/page_link/query', $args, $field, $options['post_id'] );
166 $args = apply_filters( 'acf/fields/page_link/query/name=' . $field['name'], $args, $field, $options['post_id'] );
167 $args = apply_filters( 'acf/fields/page_link/query/key=' . $field['key'], $args, $field, $options['post_id'] );
168
169 // add archives to $results
170 if ( $field['allow_archives'] && $args['paged'] == 1 ) {
171
172 // Generate unique list of URLs.
173 $links = array();
174 $links[] = home_url();
175 foreach ( $args['post_type'] as $post_type ) {
176 $links[] = get_post_type_archive_link( $post_type );
177 }
178 $links = array_filter( $links );
179 $links = array_unique( $links );
180
181 // Convert list into choices.
182 $children = array();
183 foreach ( $links as $link ) {
184
185 // Ignore if search does not match.
186 if ( $is_search && stripos( $link, $s ) === false ) {
187 continue;
188 }
189 $children[] = array(
190 'id' => $link,
191 'text' => $link,
192 );
193 }
194 if ( $children ) {
195 $results[] = array(
196 'text' => __( 'Archives', 'acf' ),
197 'children' => $children,
198 );
199 }
200 }
201
202 // If there is an include set, we will unset search to avoid attempting to further filter by the search term.
203 if ( isset( $args['include'] ) ) {
204 unset( $args['s'] );
205 }
206
207 // get posts grouped by post type
208 $groups = acf_get_grouped_posts( $args );
209
210 // loop
211 if ( ! empty( $groups ) ) {
212 foreach ( array_keys( $groups ) as $group_title ) {
213
214 // vars
215 $posts = acf_extract_var( $groups, $group_title );
216
217 // data
218 $data = array(
219 'text' => $group_title,
220 'children' => array(),
221 );
222
223 // convert post objects to post titles
224 foreach ( array_keys( $posts ) as $post_id ) {
225 $posts[ $post_id ] = $this->get_post_title( $posts[ $post_id ], $field, $options['post_id'], $is_search );
226 }
227
228 // order posts by search
229 if ( $is_search && empty( $args['orderby'] ) && isset( $args['s'] ) ) {
230 $posts = acf_order_by_search( $posts, $args['s'] );
231 }
232
233 // append to $data
234 foreach ( array_keys( $posts ) as $post_id ) {
235 $data['children'][] = $this->get_post_result( $post_id, $posts[ $post_id ] );
236 }
237
238 // append to $results
239 $results[] = $data;
240 }
241 }
242
243 // return
244 acf_send_ajax_results(
245 array(
246 'results' => $results,
247 'limit' => $args['posts_per_page'],
248 )
249 );
250 }
251
252
253 /**
254 * This function will return an array containing id, text and maybe description data
255 *
256 * @type function
257 * @date 7/07/2016
258 * @since 5.4.0
259 *
260 * @param $id (mixed)
261 * @param $text (string)
262 * @return (array)
263 */
264 function get_post_result( $id, $text ) {
265
266 // vars
267 $result = array(
268 'id' => $id,
269 'text' => $text,
270 );
271
272 // look for parent
273 $search = '| ' . __( 'Parent', 'acf' ) . ':';
274 $pos = strpos( $text, $search );
275
276 if ( $pos !== false ) {
277 $result['description'] = substr( $text, $pos + 2 );
278 $result['text'] = substr( $text, 0, $pos );
279 }
280
281 // return
282 return $result;
283 }
284
285
286 /**
287 * This function returns the HTML for a result
288 *
289 * @type function
290 * @date 1/11/2013
291 * @since 5.0.0
292 *
293 * @param $post (object)
294 * @param $field (array)
295 * @param $post_id (int) the post_id to which this value is saved to
296 * @return (string)
297 */
298 function get_post_title( $post, $field, $post_id = 0, $is_search = 0 ) {
299
300 // get post_id
301 if ( ! $post_id ) {
302 $post_id = acf_get_form_data( 'post_id' );
303 }
304
305 // vars
306 $title = acf_get_post_title( $post, $is_search );
307
308 // filters
309 $title = apply_filters( 'acf/fields/page_link/result', $title, $post, $field, $post_id );
310 $title = apply_filters( 'acf/fields/page_link/result/name=' . $field['_name'], $title, $post, $field, $post_id );
311 $title = apply_filters( 'acf/fields/page_link/result/key=' . $field['key'], $title, $post, $field, $post_id );
312
313 // return
314 return $title;
315 }
316
317
318 /**
319 * This function will return an array of posts for a given field value
320 *
321 * @type function
322 * @date 13/06/2014
323 * @since 5.0.0
324 *
325 * @param $value (array)
326 * @return $value
327 */
328 function get_posts( $value, $field ) {
329
330 // force value to array
331 $value = acf_get_array( $value );
332
333 // get selected post ID's
334 $post__in = array();
335
336 foreach ( $value as $k => $v ) {
337 if ( is_numeric( $v ) ) {
338
339 // append to $post__in
340 $post__in[] = (int) $v;
341 }
342 }
343
344 // bail early if no posts
345 if ( empty( $post__in ) ) {
346 return $value;
347 }
348
349 // get posts
350 $posts = acf_get_posts(
351 array(
352 'post__in' => $post__in,
353 'post_type' => $field['post_type'],
354 )
355 );
356
357 // override value with post
358 $return = array();
359
360 // append to $return
361 foreach ( $value as $k => $v ) {
362 if ( is_numeric( $v ) ) {
363
364 // extract first post
365 $post = array_shift( $posts );
366
367 // append
368 if ( $post ) {
369 $return[] = $post;
370 }
371 } else {
372 $return[] = $v;
373 }
374 }
375
376 // return
377 return $return;
378 }
379
380
381 /**
382 * Renders the Page Link field.
383 *
384 * @since 3.6
385 *
386 * @param array $field The field settings array.
387 * @return void
388 */
389 public function render_field( $field ) {
390 // Change Field into a select
391 $field['type'] = 'select';
392 $field['ui'] = 1;
393 $field['ajax'] = 1;
394 $field['choices'] = array();
395 $field['nonce'] = wp_create_nonce( $field['key'] );
396
397 // populate choices if value exists
398 if ( ! empty( $field['value'] ) ) {
399
400 // get posts
401 $posts = $this->get_posts( $field['value'], $field );
402
403 // set choices
404 if ( ! empty( $posts ) ) {
405 foreach ( array_keys( $posts ) as $i ) {
406
407 // vars
408 $post = acf_extract_var( $posts, $i );
409
410 if ( is_object( $post ) ) {
411
412 // append to choices
413 $field['choices'][ $post->ID ] = $this->get_post_title( $post, $field );
414 } else {
415
416 // append to choices
417 $field['choices'][ $post ] = $post;
418 }
419 }
420 }
421 }
422
423 // render
424 acf_render_field( $field );
425 }
426
427
428 /**
429 * Create extra options for your field. This is rendered when editing a field.
430 * The value of $field['name'] can be used (like bellow) to save extra data to the $field
431 *
432 * @type action
433 * @since 3.6
434 * @date 23/01/13
435 *
436 * @param $field - an array holding all the field's data
437 */
438 function render_field_settings( $field ) {
439 acf_render_field_setting(
440 $field,
441 array(
442 'label' => __( 'Filter by Post Type', 'acf' ),
443 'instructions' => '',
444 'type' => 'select',
445 'name' => 'post_type',
446 'choices' => acf_get_pretty_post_types(),
447 'multiple' => 1,
448 'ui' => 1,
449 'allow_null' => 1,
450 'placeholder' => __( 'All post types', 'acf' ),
451 )
452 );
453
454 acf_render_field_setting(
455 $field,
456 array(
457 'label' => __( 'Filter by Post Status', 'acf' ),
458 'instructions' => '',
459 'type' => 'select',
460 'name' => 'post_status',
461 'choices' => acf_get_pretty_post_statuses(),
462 'multiple' => 1,
463 'ui' => 1,
464 'allow_null' => 1,
465 'placeholder' => __( 'Any post status', 'acf' ),
466 )
467 );
468
469 acf_render_field_setting(
470 $field,
471 array(
472 'label' => __( 'Filter by Taxonomy', 'acf' ),
473 'instructions' => '',
474 'type' => 'select',
475 'name' => 'taxonomy',
476 'choices' => acf_get_taxonomy_terms(),
477 'multiple' => 1,
478 'ui' => 1,
479 'allow_null' => 1,
480 'placeholder' => __( 'All taxonomies', 'acf' ),
481 )
482 );
483
484 acf_render_field_setting(
485 $field,
486 array(
487 'label' => __( 'Allow Archives URLs', 'acf' ),
488 'instructions' => '',
489 'name' => 'allow_archives',
490 'type' => 'true_false',
491 'ui' => 1,
492 )
493 );
494
495 acf_render_field_setting(
496 $field,
497 array(
498 'label' => __( 'Select Multiple', 'acf' ),
499 'instructions' => 'Allow content editors to select multiple values',
500 'name' => 'multiple',
501 'type' => 'true_false',
502 'ui' => 1,
503 )
504 );
505 }
506
507 /**
508 * Renders the field settings used in the "Validation" tab.
509 *
510 * @since 6.0
511 *
512 * @param array $field The field settings array.
513 * @return void
514 */
515 function render_field_validation_settings( $field ) {
516 acf_render_field_setting(
517 $field,
518 array(
519 'label' => __( 'Allow Null', 'acf' ),
520 'instructions' => '',
521 'name' => 'allow_null',
522 'type' => 'true_false',
523 'ui' => 1,
524 )
525 );
526 }
527
528 /**
529 * This filter is appied to the $value after it is loaded from the db and before it is returned to the template
530 *
531 * @type filter
532 * @since 3.6
533 * @date 23/01/13
534 *
535 * @param $value (mixed) the value which was loaded from the database
536 * @param $post_id (mixed) the post_id from which the value was loaded
537 * @param $field (array) the field array holding all the field options
538 *
539 * @return $value (mixed) the modified value
540 */
541 function format_value( $value, $post_id, $field ) {
542
543 // ACF4 null
544 if ( $value === 'null' ) {
545 return false;
546 }
547
548 // bail early if no value
549 if ( empty( $value ) ) {
550 return $value;
551 }
552
553 // get posts
554 $value = $this->get_posts( $value, $field );
555
556 // set choices
557 foreach ( array_keys( $value ) as $i ) {
558
559 // vars
560 $post = acf_extract_var( $value, $i );
561
562 // convert $post to permalink
563 if ( is_object( $post ) ) {
564 $post = get_permalink( $post );
565 }
566
567 // append back to $value
568 $value[ $i ] = $post;
569 }
570
571 // convert back from array if neccessary
572 if ( ! $field['multiple'] ) {
573 $value = array_shift( $value );
574 }
575
576 // return value
577 return $value;
578 }
579
580
581 /**
582 * This filter is appied to the $value before it is updated in the db
583 *
584 * @type filter
585 * @since 3.6
586 * @date 23/01/13
587 *
588 * @param $value - the value which will be saved in the database
589 * @param $post_id - the post_id of which the value will be saved
590 * @param $field - the field array holding all the field options
591 *
592 * @return $value - the modified value
593 */
594 function update_value( $value, $post_id, $field ) {
595
596 // Bail early if no value.
597 if ( empty( $value ) ) {
598 return $value;
599 }
600
601 // Format array of values.
602 // - ensure each value is an id.
603 // - Parse each id as string for SQL LIKE queries.
604 if ( acf_is_sequential_array( $value ) ) {
605 $value = array_map( 'acf_maybe_idval', $value );
606 $value = array_map( 'strval', $value );
607
608 // Parse single value for id.
609 } else {
610 $value = acf_maybe_idval( $value );
611 }
612
613 // Return value.
614 return $value;
615 }
616
617 /**
618 * Validates page link fields updated via the REST API.
619 *
620 * @param boolean $valid The current validity booleean
621 * @param integer $value The value of the field
622 * @param array $field The field array
623 * @return boolean|WP_Error
624 */
625 public function validate_rest_value( $valid, $value, $field ) {
626 return acf_get_field_type( 'post_object' )->validate_rest_value( $valid, $value, $field );
627 }
628
629 /**
630 * Return the schema array for the REST API.
631 *
632 * @param array $field
633 * @return array
634 */
635 public function get_rest_schema( array $field ) {
636 $schema = array(
637 'type' => array( 'integer', 'array', 'null' ),
638 'required' => ! empty( $field['required'] ),
639 'items' => array(
640 'type' => array( 'integer' ),
641 ),
642 );
643
644 if ( empty( $field['allow_null'] ) ) {
645 $schema['minItems'] = 1;
646 }
647
648 if ( ! empty( $field['allow_archives'] ) ) {
649 $schema['type'][] = 'string';
650 $schema['items']['type'][] = 'string';
651 }
652
653 if ( empty( $field['multiple'] ) ) {
654 $schema['maxItems'] = 1;
655 }
656
657 return $schema;
658 }
659
660 /**
661 * @see \acf_field::get_rest_links()
662 * @param mixed $value The raw (unformatted) field value.
663 * @param integer|string $post_id
664 * @param array $field
665 * @return array
666 */
667 public function get_rest_links( $value, $post_id, array $field ) {
668 $links = array();
669
670 if ( empty( $value ) ) {
671 return $links;
672 }
673
674 foreach ( (array) $value as $object_id ) {
675 if ( ! $post_type = get_post_type( $object_id ) or ! $post_type = get_post_type_object( $post_type ) ) {
676 continue;
677 }
678 $rest_base = acf_get_object_type_rest_base( $post_type );
679 $links[] = array(
680 'rel' => $post_type->name === 'attachment' ? 'acf:attachment' : 'acf:post',
681 'href' => rest_url( sprintf( '/wp/v2/%s/%s', $rest_base, $object_id ) ),
682 'embeddable' => true,
683 );
684 }
685
686 return $links;
687 }
688
689 /**
690 * Apply basic formatting to prepare the value for default REST output.
691 *
692 * @param mixed $value
693 * @param string|integer $post_id
694 * @param array $field
695 * @return mixed
696 */
697 public function format_value_for_rest( $value, $post_id, array $field ) {
698 return acf_format_numerics( $value );
699 }
700 }
701
702
703 // initialize
704 acf_register_field_type( 'acf_field_page_link' );
705 endif; // class_exists check
706