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