/core/fields/taxonomy.php

  1. <?php 
  2.  
  3. class acf_field_taxonomy extends acf_field 
  4. /** 
  5. * __construct 
  6. * 
  7. * Set name / label needed for actions / filters 
  8. * 
  9. * @since 3.6 
  10. * @date 23/01/13 
  11. */ 
  12.  
  13. function __construct() 
  14. // vars 
  15. $this->name = 'taxonomy'; 
  16. $this->label = __("Taxonomy", 'acf'); 
  17. $this->category = __("Relational", 'acf'); 
  18. $this->defaults = array( 
  19. 'taxonomy' => 'category',  
  20. 'field_type' => 'checkbox',  
  21. 'allow_null' => 0,  
  22. 'load_save_terms' => 0,  
  23. 'multiple' => 0,  
  24. 'return_format' => 'id' 
  25. ); 
  26.  
  27.  
  28. // do not delete! 
  29. parent::__construct(); 
  30.  
  31.  
  32.  
  33. /** 
  34. * get_terms 
  35. * 
  36. * This function will return an array of terms for a given field value 
  37. * 
  38. * @type function 
  39. * @date 13/06/2014 
  40. * @since 5.0.0 
  41. * 
  42. * @param $value (array) 
  43. * @return $value 
  44. */ 
  45.  
  46. function get_terms( $value, $taxonomy = 'category' ) { 
  47.  
  48. // load terms in 1 query to save multiple DB calls from following code 
  49. if( count($value) > 1 ) { 
  50.  
  51. $terms = get_terms($taxonomy, array( 
  52. 'hide_empty' => false,  
  53. 'include' => $value,  
  54. )); 
  55.  
  56.  
  57.  
  58. // update value to include $post 
  59. foreach( array_keys($value) as $i ) { 
  60.  
  61. $value[ $i ] = get_term( $value[ $i ], $taxonomy ); 
  62.  
  63.  
  64.  
  65. // filter out null values 
  66. $value = array_filter($value); 
  67.  
  68.  
  69. // return 
  70. return $value; 
  71.  
  72.  
  73. /** 
  74. * load_value() 
  75. * 
  76. * This filter is appied to the $value after it is loaded from the db 
  77. * 
  78. * @type filter 
  79. * @since 3.6 
  80. * @date 23/01/13 
  81. * 
  82. * @param $value - the value found in the database 
  83. * @param $post_id - the $post_id from which the value was loaded from 
  84. * @param $field - the field array holding all the field options 
  85. * 
  86. * @return $value - the value to be saved in te database 
  87. */ 
  88.  
  89. function load_value( $value, $post_id, $field ) { 
  90.  
  91. // get valid terms 
  92. $value = acf_get_valid_terms($value, $field['taxonomy']); 
  93.  
  94.  
  95. // load/save 
  96. if( $field['load_save_terms'] ) { 
  97.  
  98. // bail early if no value 
  99. if( empty($value) ) { 
  100.  
  101. return $value; 
  102.  
  103.  
  104.  
  105. // get current ID's 
  106. $term_ids = wp_get_object_terms($post_id, $field['taxonomy'], array('fields' => 'ids', 'orderby' => 'none')); 
  107.  
  108.  
  109. // case 
  110. if( empty($term_ids) ) { 
  111.  
  112. // 1. no terms for this post 
  113. return null; 
  114.  
  115. } elseif( is_array($value) ) { 
  116.  
  117. // 2. remove metadata terms which are no longer for this post 
  118. $value = array_map('intval', $value); 
  119. $value = array_intersect( $value, $term_ids ); 
  120.  
  121. } elseif( !in_array($value, $term_ids)) { 
  122.  
  123. // 3. term is no longer for this post 
  124. return null; 
  125.  
  126.  
  127.  
  128.  
  129. // return 
  130. return $value; 
  131.  
  132.  
  133. /** 
  134. * update_value() 
  135. * 
  136. * This filter is appied to the $value before it is updated in the db 
  137. * 
  138. * @type filter 
  139. * @since 3.6 
  140. * @date 23/01/13 
  141. * 
  142. * @param $value - the value which will be saved in the database 
  143. * @param $field - the field array holding all the field options 
  144. * @param $post_id - the $post_id of which the value will be saved 
  145. * 
  146. * @return $value - the modified value 
  147. */ 
  148.  
  149. function update_value( $value, $post_id, $field ) { 
  150.  
  151. // vars 
  152. if( is_array($value) ) { 
  153.  
  154. $value = array_filter($value); 
  155.  
  156.  
  157.  
  158. // load_save_terms 
  159. if( $field['load_save_terms'] ) { 
  160.  
  161. // vars 
  162. $taxonomy = $field['taxonomy']; 
  163.  
  164.  
  165. // force value to array 
  166. $term_ids = acf_force_type_array( $value ); 
  167.  
  168.  
  169. // convert to int 
  170. $term_ids = array_map('intval', $term_ids); 
  171.  
  172.  
  173. // bypass $this->set_terms if called directly from update_field 
  174. if( !did_action('acf/save_post') ) { 
  175.  
  176. wp_set_object_terms( $post_id, $term_ids, $taxonomy, false ); 
  177.  
  178. return $value; 
  179.  
  180.  
  181.  
  182. // initialize 
  183. if( empty($this->set_terms) ) { 
  184.  
  185. // create holder 
  186. $this->set_terms = array(); 
  187.  
  188.  
  189. // add action 
  190. add_action('acf/save_post', array($this, 'set_terms'), 15, 1); 
  191.  
  192.  
  193.  
  194. // append 
  195. if( empty($this->set_terms[ $taxonomy ]) ) { 
  196.  
  197. $this->set_terms[ $taxonomy ] = array(); 
  198.  
  199.  
  200. $this->set_terms[ $taxonomy ] = array_merge($this->set_terms[ $taxonomy ], $term_ids); 
  201.  
  202.  
  203.  
  204. // return 
  205. return $value; 
  206.  
  207.  
  208.  
  209. /** 
  210. * set_terms 
  211. * 
  212. * description 
  213. * 
  214. * @type function 
  215. * @date 26/11/2014 
  216. * @since 5.0.9 
  217. * 
  218. * @param $post_id (int) 
  219. * @return $post_id (int) 
  220. */ 
  221.  
  222. function set_terms( $post_id ) { 
  223.  
  224. // bail ealry if no terms 
  225. if( empty($this->set_terms) ) { 
  226.  
  227. return; 
  228.  
  229.  
  230.  
  231. // loop over terms 
  232. foreach( $this->set_terms as $taxonomy => $term_ids ) { 
  233.  
  234. wp_set_object_terms( $post_id, $term_ids, $taxonomy, false ); 
  235.  
  236.  
  237.  
  238. // reset array ( WP saves twice ) 
  239. $this->set_terms = array(); 
  240.  
  241.  
  242.  
  243. /** 
  244. * format_value_for_api() 
  245. * 
  246. * This filter is appied to the $value after it is loaded from the db and before it is passed back to the api functions such as the_field 
  247. * 
  248. * @type filter 
  249. * @since 3.6 
  250. * @date 23/01/13 
  251. * 
  252. * @param $value - the value which was loaded from the database 
  253. * @param $post_id - the $post_id from which the value was loaded 
  254. * @param $field - the field array holding all the field options 
  255. * 
  256. * @return $value - the modified value 
  257. */ 
  258.  
  259. function format_value_for_api( $value, $post_id, $field ) { 
  260.  
  261. // bail early if no value 
  262. if( empty($value) ) { 
  263.  
  264. return $value; 
  265.  
  266.  
  267.  
  268. // force value to array 
  269. $value = acf_force_type_array( $value ); 
  270.  
  271.  
  272. // convert values to int 
  273. $value = array_map('intval', $value); 
  274.  
  275.  
  276. // load posts if needed 
  277. if( $field['return_format'] == 'object' ) { 
  278.  
  279.  
  280. // get posts 
  281. $value = $this->get_terms( $value, $field["taxonomy"] ); 
  282.  
  283.  
  284.  
  285. // convert back from array if neccessary 
  286. if( $field['field_type'] == 'select' || $field['field_type'] == 'radio' ) { 
  287.  
  288. $value = array_shift($value); 
  289.  
  290.  
  291.  
  292. // return 
  293. return $value; 
  294.  
  295.  
  296. /** 
  297. * create_field() 
  298. * 
  299. * Create the HTML interface for your field 
  300. * 
  301. * @type action 
  302. * @since 3.6 
  303. * @date 23/01/13 
  304. * 
  305. * @param $field - an array holding all the field's data 
  306. */ 
  307.  
  308. function create_field( $field ) 
  309. // vars 
  310. $single_name = $field['name']; 
  311.  
  312.  
  313. // multi select? 
  314. if( $field['field_type'] == 'multi_select' ) 
  315. $field['multiple'] = 1; 
  316. $field['field_type'] = 'select'; 
  317. $field['name'] .= '[]'; 
  318. elseif( $field['field_type'] == 'checkbox' ) 
  319. $field['name'] .= '[]'; 
  320.  
  321. // value must be array! 
  322. if( !is_array($field['value']) ) 
  323. $field['value'] = array( $field['value'] ); 
  324.  
  325.  
  326. // vars 
  327. $args = array( 
  328. 'taxonomy' => $field['taxonomy'],  
  329. 'hide_empty' => false,  
  330. 'style' => 'none',  
  331. 'walker' => new acf_taxonomy_field_walker( $field ),  
  332. ); 
  333.  
  334. $args = apply_filters('acf/fields/taxonomy/wp_list_categories', $args, $field ); 
  335.  
  336. ?> 
  337. <div class="acf-taxonomy-field" data-load_save="<?php echo $field['load_save_terms']; ?>"> 
  338. <input type="hidden" name="<?php echo $single_name; ?>" value="" /> 
  339.  
  340. <?php if( $field['field_type'] == 'select' ): ?> 
  341.  
  342. <select id="<?php echo $field['id']; ?>" name="<?php echo $field['name']; ?>" <?php if( $field['multiple'] ): ?>multiple="multiple" size="5"<?php endif; ?>> 
  343. <?php if( $field['allow_null'] ): ?> 
  344. <option value=""><?php _e("None", 'acf'); ?></option> 
  345. <?php endif; ?> 
  346.  
  347. <?php else: ?> 
  348. <div class="categorychecklist-holder"> 
  349. <ul class="acf-checkbox-list"> 
  350. <?php if( $field['allow_null'] ): ?> 
  351. <li> 
  352. <label class="selectit"> 
  353. <input type="<?php echo $field['field_type']; ?>" name="<?php echo $field['name']; ?>" value="" /> <?php _e("None", 'acf'); ?> 
  354. </label> 
  355. </li> 
  356. <?php endif; ?> 
  357.  
  358. <?php endif; ?> 
  359.  
  360. <?php wp_list_categories( $args ); ?> 
  361.  
  362. <?php if( $field['field_type'] == 'select' ): ?> 
  363.  
  364. </select> 
  365.  
  366. <?php else: ?> 
  367.  
  368. </ul> 
  369. </div> 
  370.  
  371. <?php endif; ?> 
  372.  
  373. </div> 
  374. <?php 
  375.  
  376.  
  377.  
  378. /** 
  379. * create_options() 
  380. * 
  381. * Create extra options for your field. This is rendered when editing a field. 
  382. * The value of $field['name'] can be used (like bellow) to save extra data to the $field 
  383. * 
  384. * @type action 
  385. * @since 3.6 
  386. * @date 23/01/13 
  387. * 
  388. * @param $field - an array holding all the field's data 
  389. */ 
  390.  
  391. function create_options( $field ) 
  392. // vars 
  393. $key = $field['name']; 
  394.  
  395. ?> 
  396. <tr class="field_option field_option_<?php echo $this->name; ?>"> 
  397. <td class="label"> 
  398. <label><?php _e("Taxonomy", 'acf'); ?></label> 
  399. </td> 
  400. <td> 
  401. <?php 
  402.  
  403. // vars 
  404. $choices = array(); 
  405. $taxonomies = get_taxonomies( array(), 'objects' ); 
  406. $ignore = array( 'post_format', 'nav_menu', 'link_category' ); 
  407.  
  408.  
  409. foreach( $taxonomies as $taxonomy ) 
  410. if( in_array($taxonomy->name, $ignore) ) 
  411. continue; 
  412.  
  413. $choices[ $taxonomy->name ] = $taxonomy->name; 
  414.  
  415.  
  416. do_action('acf/create_field', array( 
  417. 'type' => 'select',  
  418. 'name' => 'fields['.$key.'][taxonomy]',  
  419. 'value' => $field['taxonomy'],  
  420. 'choices' => $choices,  
  421. )); 
  422.  
  423. ?> 
  424. </td> 
  425. </tr> 
  426. <tr class="field_option field_option_<?php echo $this->name; ?>"> 
  427. <td class="label"> 
  428. <label><?php _e("Field Type", 'acf'); ?></label> 
  429. </td> 
  430. <td> 
  431. <?php  
  432. do_action('acf/create_field', array( 
  433. 'type' => 'select',  
  434. 'name' => 'fields['.$key.'][field_type]',  
  435. 'value' => $field['field_type'],  
  436. 'optgroup' => true,  
  437. 'choices' => array( 
  438. __("Multiple Values", 'acf') => array( 
  439. 'checkbox' => __('Checkbox', 'acf'),  
  440. 'multi_select' => __('Multi Select', 'acf') 
  441. ),  
  442. __("Single Value", 'acf') => array( 
  443. 'radio' => __('Radio Buttons', 'acf'),  
  444. 'select' => __('Select', 'acf') 
  445. )); 
  446. ?> 
  447. </td> 
  448. </tr> 
  449. <tr class="field_option field_option_<?php echo $this->name; ?>"> 
  450. <td class="label"> 
  451. <label><?php _e("Allow Null?", 'acf'); ?></label> 
  452. </td> 
  453. <td> 
  454. <?php  
  455. do_action('acf/create_field', array( 
  456. 'type' => 'radio',  
  457. 'name' => 'fields['.$key.'][allow_null]',  
  458. 'value' => $field['allow_null'],  
  459. 'choices' => array( 
  460. 1 => __("Yes", 'acf'),  
  461. 0 => __("No", 'acf'),  
  462. ),  
  463. 'layout' => 'horizontal',  
  464. )); 
  465. ?> 
  466. </td> 
  467. </tr> 
  468. <tr class="field_option field_option_<?php echo $this->name; ?>"> 
  469. <td class="label"> 
  470. <label><?php _e("Load & Save Terms to Post", 'acf'); ?></label> 
  471. </td> 
  472. <td> 
  473. <?php  
  474. do_action('acf/create_field', array( 
  475. 'type' => 'true_false',  
  476. 'name' => 'fields['.$key.'][load_save_terms]',  
  477. 'value' => $field['load_save_terms'],  
  478. 'message' => __("Load value based on the post's terms and update the post's terms on save", 'acf') 
  479. )); 
  480. ?> 
  481. </td> 
  482. </tr> 
  483. <tr class="field_option field_option_<?php echo $this->name; ?>"> 
  484. <td class="label"> 
  485. <label><?php _e("Return Value", 'acf'); ?></label> 
  486. </td> 
  487. <td> 
  488. <?php 
  489. do_action('acf/create_field', array( 
  490. 'type' => 'radio',  
  491. 'name' => 'fields['.$key.'][return_format]',  
  492. 'value' => $field['return_format'],  
  493. 'layout' => 'horizontal',  
  494. 'choices' => array( 
  495. 'object' => __("Term Object", 'acf'),  
  496. 'id' => __("Term ID", 'acf') 
  497. )); 
  498. ?> 
  499. </td> 
  500. </tr> 
  501. <?php 
  502.  
  503.  
  504.  
  505.  
  506. new acf_field_taxonomy(); 
  507.  
  508.  
  509. class acf_taxonomy_field_walker extends Walker 
  510. // vars 
  511. var $field = null,  
  512. $tree_type = 'category',  
  513. $db_fields = array ( 'parent' => 'parent', 'id' => 'term_id' ); 
  514.  
  515.  
  516. // construct 
  517. function __construct( $field ) 
  518. $this->field = $field; 
  519.  
  520.  
  521. // start_el 
  522. function start_el( &$output, $term, $depth = 0, $args = array(), $current_object_id = 0) 
  523. // vars 
  524. $selected = in_array( $term->term_id, $this->field['value'] ); 
  525.  
  526. if( $this->field['field_type'] == 'checkbox' ) 
  527. $output .= '<li><label class="selectit"><input type="checkbox" name="' . $this->field['name'] . '" value="' . $term->term_id . '" ' . ($selected ? 'checked="checked"' : '') . ' /> ' . $term->name . '</label>'; 
  528. elseif( $this->field['field_type'] == 'radio' ) 
  529. $output .= '<li><label class="selectit"><input type="radio" name="' . $this->field['name'] . '" value="' . $term->term_id . '" ' . ($selected ? 'checked="checkbox"' : '') . ' /> ' . $term->name . '</label>'; 
  530. elseif( $this->field['field_type'] == 'select' ) 
  531. $indent = str_repeat("— ", $depth); 
  532. $output .= '<option value="' . $term->term_id . '" ' . ($selected ? 'selected="selected"' : '') . '>' . $indent . $term->name . '</option>'; 
  533.  
  534.  
  535.  
  536. //end_el 
  537. function end_el( &$output, $term, $depth = 0, $args = array() ) 
  538. if( in_array($this->field['field_type'], array('checkbox', 'radio')) ) 
  539. $output .= '</li>'; 
  540.  
  541. $output .= "\n"; 
  542.  
  543.  
  544. // start_lvl 
  545. function start_lvl( &$output, $depth = 0, $args = array() ) 
  546. // indent 
  547. //$output .= str_repeat( "\t", $depth); 
  548.  
  549.  
  550. // wrap element 
  551. if( in_array($this->field['field_type'], array('checkbox', 'radio')) ) 
  552. $output .= '<ul class="children">' . "\n"; 
  553.  
  554.  
  555. // end_lvl 
  556. function end_lvl( &$output, $depth = 0, $args = array() ) 
  557. // indent 
  558. //$output .= str_repeat( "\t", $depth); 
  559.  
  560.  
  561. // wrap element 
  562. if( in_array($this->field['field_type'], array('checkbox', 'radio')) ) 
  563. $output .= '</ul>' . "\n"; 
  564.  
  565.  
  566. ?> 
.