276 * * You can see accepted values in {@link get_taxonomy_labels()}. |
269 * * You can see accepted values in {@link get_taxonomy_labels()}. |
277 * - description - A short descriptive summary of what the taxonomy is for. Defaults to blank. |
270 * - description - A short descriptive summary of what the taxonomy is for. Defaults to blank. |
278 * - public - If the taxonomy should be publicly queryable; //@TODO not implemented. |
271 * - public - If the taxonomy should be publicly queryable; //@TODO not implemented. |
279 * * Defaults to true. |
272 * * Defaults to true. |
280 * - hierarchical - Whether the taxonomy is hierarchical (e.g. category). Defaults to false. |
273 * - hierarchical - Whether the taxonomy is hierarchical (e.g. category). Defaults to false. |
281 * - show_ui -Whether to generate a default UI for managing this taxonomy in the admin. |
274 * - show_ui - Whether to generate a default UI for managing this taxonomy in the admin. |
282 * * If not set, the default is inherited from public. |
275 * * If not set, the default is inherited from public. |
283 * - show_in_menu - Where to show the taxonomy in the admin menu. |
276 * - show_in_menu - Whether to show the taxonomy in the admin menu. |
284 * * If true, the taxonomy is shown as a submenu of the object type menu. |
277 * * If true, the taxonomy is shown as a submenu of the object type menu. |
285 * * If false, no menu is shown. |
278 * * If false, no menu is shown. |
286 * * show_ui must be true. |
279 * * show_ui must be true. |
287 * * If not set, the default is inherited from show_ui. |
280 * * If not set, the default is inherited from show_ui. |
288 * - show_in_nav_menus - Makes this taxonomy available for selection in navigation menus. |
281 * - show_in_nav_menus - Makes this taxonomy available for selection in navigation menus. |
289 * * If not set, the default is inherited from public. |
282 * * If not set, the default is inherited from public. |
290 * - show_tagcloud - Whether to list the taxonomy in the Tag Cloud Widget. |
283 * - show_tagcloud - Whether to list the taxonomy in the Tag Cloud Widget. |
291 * * If not set, the default is inherited from show_ui. |
284 * * If not set, the default is inherited from show_ui. |
292 * - meta_box_cb - Provide a callback function for the meta box display. Defaults to |
285 * - show_in_quick_edit - Whether to show the taxonomy in the quick/bulk edit panel. |
293 * post_categories_meta_box for hierarchical taxonomies and post_tags_meta_box for non-hierarchical. |
286 * * It not set, the default is inherited from show_ui. |
|
287 * - show_admin_column - Whether to display a column for the taxonomy on its post type listing screens. |
|
288 * * Defaults to false. |
|
289 * - meta_box_cb - Provide a callback function for the meta box display. |
|
290 * * If not set, defaults to post_categories_meta_box for hierarchical taxonomies |
|
291 * and post_tags_meta_box for non-hierarchical. |
|
292 * * If false, no meta box is shown. |
294 * - capabilities - Array of capabilities for this taxonomy. |
293 * - capabilities - Array of capabilities for this taxonomy. |
295 * * You can see accepted values in this function. |
294 * * You can see accepted values in this function. |
296 * - rewrite - Triggers the handling of rewrites for this taxonomy. Defaults to true, using $taxonomy as slug. |
295 * - rewrite - Triggers the handling of rewrites for this taxonomy. Defaults to true, using $taxonomy as slug. |
297 * * To prevent rewrite, set to false. |
296 * * To prevent rewrite, set to false. |
298 * * To specify rewrite rules, an array can be passed with any of these keys |
297 * * To specify rewrite rules, an array can be passed with any of these keys |
415 $wp_taxonomies[ $taxonomy ] = (object) $args; |
425 $wp_taxonomies[ $taxonomy ] = (object) $args; |
416 |
426 |
417 // register callback handling for metabox |
427 // register callback handling for metabox |
418 add_filter( 'wp_ajax_add-' . $taxonomy, '_wp_ajax_add_hierarchical_term' ); |
428 add_filter( 'wp_ajax_add-' . $taxonomy, '_wp_ajax_add_hierarchical_term' ); |
419 |
429 |
|
430 /** |
|
431 * Fires after a taxonomy is registered. |
|
432 * |
|
433 * @since 3.3.0 |
|
434 * |
|
435 * @param string $taxonomy Taxonomy slug. |
|
436 * @param array|string $object_type Object type or array of object types. |
|
437 * @param array $args Array of taxonomy registration arguments. |
|
438 */ |
420 do_action( 'registered_taxonomy', $taxonomy, $object_type, $args ); |
439 do_action( 'registered_taxonomy', $taxonomy, $object_type, $args ); |
421 } |
440 } |
422 |
441 |
423 /** |
442 /** |
424 * Builds an object with all taxonomy labels out of a taxonomy object |
443 * Builds an object with all taxonomy labels out of a taxonomy object |
425 * |
444 * |
426 * Accepted keys of the label array in the taxonomy object: |
445 * Accepted keys of the label array in the taxonomy object: |
|
446 * |
427 * - name - general name for the taxonomy, usually plural. The same as and overridden by $tax->label. Default is Tags/Categories |
447 * - name - general name for the taxonomy, usually plural. The same as and overridden by $tax->label. Default is Tags/Categories |
428 * - singular_name - name for one object of this taxonomy. Default is Tag/Category |
448 * - singular_name - name for one object of this taxonomy. Default is Tag/Category |
429 * - search_items - Default is Search Tags/Search Categories |
449 * - search_items - Default is Search Tags/Search Categories |
430 * - popular_items - This string isn't used on hierarchical taxonomies. Default is Popular Tags |
450 * - popular_items - This string isn't used on hierarchical taxonomies. Default is Popular Tags |
431 * - all_items - Default is All Tags/All Categories |
451 * - all_items - Default is All Tags/All Categories |
432 * - parent_item - This string isn't used on non-hierarchical taxonomies. In hierarchical ones the default is Parent Category |
452 * - parent_item - This string isn't used on non-hierarchical taxonomies. In hierarchical ones the default is Parent Category |
433 * - parent_item_colon - The same as <code>parent_item</code>, but with colon <code>:</code> in the end |
453 * - parent_item_colon - The same as `parent_item`, but with colon `:` in the end |
434 * - edit_item - Default is Edit Tag/Edit Category |
454 * - edit_item - Default is Edit Tag/Edit Category |
435 * - view_item - Default is View Tag/View Category |
455 * - view_item - Default is View Tag/View Category |
436 * - update_item - Default is Update Tag/Update Category |
456 * - update_item - Default is Update Tag/Update Category |
437 * - add_new_item - Default is Add New Tag/Add New Category |
457 * - add_new_item - Default is Add New Tag/Add New Category |
438 * - new_item_name - Default is New Tag Name/New Category Name |
458 * - new_item_name - Default is New Tag Name/New Category Name |
439 * - separate_items_with_commas - This string isn't used on hierarchical taxonomies. Default is "Separate tags with commas", used in the meta box. |
459 * - separate_items_with_commas - This string isn't used on hierarchical taxonomies. Default is "Separate tags with commas", used in the meta box. |
440 * - add_or_remove_items - This string isn't used on hierarchical taxonomies. Default is "Add or remove tags", used in the meta box when JavaScript is disabled. |
460 * - add_or_remove_items - This string isn't used on hierarchical taxonomies. Default is "Add or remove tags", used in the meta box when JavaScript is disabled. |
441 * - choose_from_most_used - This string isn't used on hierarchical taxonomies. Default is "Choose from the most used tags", used in the meta box. |
461 * - choose_from_most_used - This string isn't used on hierarchical taxonomies. Default is "Choose from the most used tags", used in the meta box. |
442 * - not_found - This string isn't used on hierarchical taxonomies. Default is "No tags found", used in the meta box. |
462 * - not_found - Default is "No tags found"/"No categories found", used in the meta box and taxonomy list table. |
443 * |
463 * |
444 * Above, the first default value is for non-hierarchical taxonomies (like tags) and the second one is for hierarchical taxonomies (like categories). |
464 * Above, the first default value is for non-hierarchical taxonomies (like tags) and the second one is for hierarchical taxonomies (like categories). |
445 * |
465 * |
446 * @since 3.0.0 |
466 * @since 3.0.0 |
447 * @param object $tax Taxonomy object |
467 * @param object $tax Taxonomy object |
550 * |
568 * |
551 * It is possible to change the order that object_ids is returned by either |
569 * It is possible to change the order that object_ids is returned by either |
552 * using PHP sort family functions or using the database by using $args with |
570 * using PHP sort family functions or using the database by using $args with |
553 * either ASC or DESC array. The value should be in the key named 'order'. |
571 * either ASC or DESC array. The value should be in the key named 'order'. |
554 * |
572 * |
555 * @package WordPress |
|
556 * @subpackage Taxonomy |
|
557 * @since 2.3.0 |
573 * @since 2.3.0 |
558 * |
574 * |
559 * @uses $wpdb |
575 * @global wpdb $wpdb WordPress database abstraction object. |
560 * @uses wp_parse_args() Creates an array from string $args. |
|
561 * |
576 * |
562 * @param int|array $term_ids Term id or array of term ids of terms that will be used |
577 * @param int|array $term_ids Term id or array of term ids of terms that will be used |
563 * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names |
578 * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names |
564 * @param array|string $args Change the order of the object_ids, either ASC or DESC |
579 * @param array|string $args Change the order of the object_ids, either ASC or DESC |
565 * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success |
580 * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success |
566 * the array can be empty meaning that there are no $object_ids found or it will return the $object_ids found. |
581 * the array can be empty meaning that there are no $object_ids found or it will return the $object_ids found. |
567 */ |
582 */ |
568 function get_objects_in_term( $term_ids, $taxonomies, $args = array() ) { |
583 function get_objects_in_term( $term_ids, $taxonomies, $args = array() ) { |
569 global $wpdb; |
584 global $wpdb; |
570 |
585 |
571 if ( ! is_array( $term_ids ) ) |
586 if ( ! is_array( $term_ids ) ) { |
572 $term_ids = array( $term_ids ); |
587 $term_ids = array( $term_ids ); |
573 |
588 } |
574 if ( ! is_array( $taxonomies ) ) |
589 if ( ! is_array( $taxonomies ) ) { |
575 $taxonomies = array( $taxonomies ); |
590 $taxonomies = array( $taxonomies ); |
576 |
591 } |
577 foreach ( (array) $taxonomies as $taxonomy ) { |
592 foreach ( (array) $taxonomies as $taxonomy ) { |
578 if ( ! taxonomy_exists( $taxonomy ) ) |
593 if ( ! taxonomy_exists( $taxonomy ) ) { |
579 return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) ); |
594 return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) ); |
|
595 } |
580 } |
596 } |
581 |
597 |
582 $defaults = array( 'order' => 'ASC' ); |
598 $defaults = array( 'order' => 'ASC' ); |
583 $args = wp_parse_args( $args, $defaults ); |
599 $args = wp_parse_args( $args, $defaults ); |
584 extract( $args, EXTR_SKIP ); |
600 |
585 |
601 $order = ( 'desc' == strtolower( $args['order'] ) ) ? 'DESC' : 'ASC'; |
586 $order = ( 'desc' == strtolower( $order ) ) ? 'DESC' : 'ASC'; |
|
587 |
602 |
588 $term_ids = array_map('intval', $term_ids ); |
603 $term_ids = array_map('intval', $term_ids ); |
589 |
604 |
590 $taxonomies = "'" . implode( "', '", $taxonomies ) . "'"; |
605 $taxonomies = "'" . implode( "', '", $taxonomies ) . "'"; |
591 $term_ids = "'" . implode( "', '", $term_ids ) . "'"; |
606 $term_ids = "'" . implode( "', '", $term_ids ) . "'"; |
592 |
607 |
593 $object_ids = $wpdb->get_col("SELECT tr.object_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND tt.term_id IN ($term_ids) ORDER BY tr.object_id $order"); |
608 $object_ids = $wpdb->get_col("SELECT tr.object_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND tt.term_id IN ($term_ids) ORDER BY tr.object_id $order"); |
594 |
609 |
595 if ( ! $object_ids ) |
610 if ( ! $object_ids ){ |
596 return array(); |
611 return array(); |
597 |
612 } |
598 return $object_ids; |
613 return $object_ids; |
599 } |
614 } |
600 |
615 |
601 /** |
616 /** |
602 * Given a taxonomy query, generates SQL to be appended to a main query. |
617 * Given a taxonomy query, generates SQL to be appended to a main query. |
655 * |
666 * |
656 * @since 3.2.0 |
667 * @since 3.2.0 |
657 * @access private |
668 * @access private |
658 * @var string |
669 * @var string |
659 */ |
670 */ |
660 private static $no_results = array( 'join' => '', 'where' => ' AND 0 = 1' ); |
671 private static $no_results = array( 'join' => array( '' ), 'where' => array( '0 = 1' ) ); |
|
672 |
|
673 /** |
|
674 * A flat list of table aliases used in the JOIN clauses. |
|
675 * |
|
676 * @since 4.1.0 |
|
677 * @access protected |
|
678 * @var array |
|
679 */ |
|
680 protected $table_aliases = array(); |
|
681 |
|
682 /** |
|
683 * Terms and taxonomies fetched by this query. |
|
684 * |
|
685 * We store this data in a flat array because they are referenced in a |
|
686 * number of places by {@see WP_Query}. |
|
687 * |
|
688 * @since 4.1.0 |
|
689 * @access public |
|
690 * @var array |
|
691 */ |
|
692 public $queried_terms = array(); |
|
693 |
|
694 /** |
|
695 * Database table that where the metadata's objects are stored (eg $wpdb->users). |
|
696 * |
|
697 * @since 4.1.0 |
|
698 * @access public |
|
699 * @var string |
|
700 */ |
|
701 public $primary_table; |
|
702 |
|
703 /** |
|
704 * Column in 'primary_table' that represents the ID of the object. |
|
705 * |
|
706 * @since 4.1.0 |
|
707 * @access public |
|
708 * @var string |
|
709 */ |
|
710 public $primary_id_column; |
661 |
711 |
662 /** |
712 /** |
663 * Constructor. |
713 * Constructor. |
664 * |
714 * |
665 * Parses a compact tax query and sets defaults. |
|
666 * |
|
667 * @since 3.1.0 |
715 * @since 3.1.0 |
|
716 * @since 4.1.0 Added support for `$operator` 'NOT EXISTS' and 'EXISTS' values. |
668 * @access public |
717 * @access public |
669 * |
718 * |
670 * @param array $tax_query A compact tax query: |
719 * @param array $tax_query { |
671 * array( |
720 * Array of taxonomy query clauses. |
672 * 'relation' => 'OR', |
721 * |
673 * array( |
722 * @type string $relation Optional. The MySQL keyword used to join |
674 * 'taxonomy' => 'tax1', |
723 * the clauses of the query. Accepts 'AND', or 'OR'. Default 'AND'. |
675 * 'terms' => array( 'term1', 'term2' ), |
724 * @type array { |
676 * 'field' => 'slug', |
725 * Optional. An array of first-order clause parameters, or another fully-formed tax query. |
677 * ), |
726 * |
678 * array( |
727 * @type string $taxonomy Taxonomy being queried. Optional when field=term_taxonomy_id. |
679 * 'taxonomy' => 'tax2', |
728 * @type string|int|array $terms Term or terms to filter by. |
680 * 'terms' => array( 'term-a', 'term-b' ), |
729 * @type string $field Field to match $terms against. Accepts 'term_id', 'slug', |
681 * 'field' => 'slug', |
730 * 'name', or 'term_taxonomy_id'. Default: 'term_id'. |
682 * ), |
731 * @type string $operator MySQL operator to be used with $terms in the WHERE clause. |
683 * ) |
732 * Accepts 'AND', 'IN', 'NOT IN', 'EXISTS', 'NOT EXISTS'. |
|
733 * Default: 'IN'. |
|
734 * @type bool $include_children Optional. Whether to include child terms. |
|
735 * Requires a $taxonomy. Default: true. |
|
736 * } |
|
737 * } |
684 */ |
738 */ |
685 public function __construct( $tax_query ) { |
739 public function __construct( $tax_query ) { |
686 if ( isset( $tax_query['relation'] ) && strtoupper( $tax_query['relation'] ) == 'OR' ) { |
740 if ( isset( $tax_query['relation'] ) ) { |
687 $this->relation = 'OR'; |
741 $this->relation = $this->sanitize_relation( $tax_query['relation'] ); |
688 } else { |
742 } else { |
689 $this->relation = 'AND'; |
743 $this->relation = 'AND'; |
690 } |
744 } |
|
745 |
|
746 $this->queries = $this->sanitize_query( $tax_query ); |
|
747 } |
|
748 |
|
749 /** |
|
750 * Ensure the 'tax_query' argument passed to the class constructor is well-formed. |
|
751 * |
|
752 * Ensures that each query-level clause has a 'relation' key, and that |
|
753 * each first-order clause contains all the necessary keys from `$defaults`. |
|
754 * |
|
755 * @since 4.1.0 |
|
756 * @access public |
|
757 * |
|
758 * @param array $queries Array of queries clauses. |
|
759 * @return array Sanitized array of query clauses. |
|
760 */ |
|
761 public function sanitize_query( $queries ) { |
|
762 $cleaned_query = array(); |
691 |
763 |
692 $defaults = array( |
764 $defaults = array( |
693 'taxonomy' => '', |
765 'taxonomy' => '', |
694 'terms' => array(), |
766 'terms' => array(), |
695 'include_children' => true, |
|
696 'field' => 'term_id', |
767 'field' => 'term_id', |
697 'operator' => 'IN', |
768 'operator' => 'IN', |
|
769 'include_children' => true, |
698 ); |
770 ); |
699 |
771 |
700 foreach ( $tax_query as $query ) { |
772 foreach ( $queries as $key => $query ) { |
701 if ( ! is_array( $query ) ) |
773 if ( 'relation' === $key ) { |
702 continue; |
774 $cleaned_query['relation'] = $this->sanitize_relation( $query ); |
703 |
775 |
704 $query = array_merge( $defaults, $query ); |
776 // First-order clause. |
705 |
777 } elseif ( self::is_first_order_clause( $query ) ) { |
706 $query['terms'] = (array) $query['terms']; |
778 |
707 |
779 $cleaned_clause = array_merge( $defaults, $query ); |
708 $this->queries[] = $query; |
780 $cleaned_clause['terms'] = (array) $cleaned_clause['terms']; |
709 } |
781 $cleaned_query[] = $cleaned_clause; |
|
782 |
|
783 /* |
|
784 * Keep a copy of the clause in the flate |
|
785 * $queried_terms array, for use in WP_Query. |
|
786 */ |
|
787 if ( ! empty( $cleaned_clause['taxonomy'] ) && 'NOT IN' !== $cleaned_clause['operator'] ) { |
|
788 $taxonomy = $cleaned_clause['taxonomy']; |
|
789 if ( ! isset( $this->queried_terms[ $taxonomy ] ) ) { |
|
790 $this->queried_terms[ $taxonomy ] = array(); |
|
791 } |
|
792 |
|
793 /* |
|
794 * Backward compatibility: Only store the first |
|
795 * 'terms' and 'field' found for a given taxonomy. |
|
796 */ |
|
797 if ( ! empty( $cleaned_clause['terms'] ) && ! isset( $this->queried_terms[ $taxonomy ]['terms'] ) ) { |
|
798 $this->queried_terms[ $taxonomy ]['terms'] = $cleaned_clause['terms']; |
|
799 } |
|
800 |
|
801 if ( ! empty( $cleaned_clause['field'] ) && ! isset( $this->queried_terms[ $taxonomy ]['field'] ) ) { |
|
802 $this->queried_terms[ $taxonomy ]['field'] = $cleaned_clause['field']; |
|
803 } |
|
804 } |
|
805 |
|
806 // Otherwise, it's a nested query, so we recurse. |
|
807 } elseif ( is_array( $query ) ) { |
|
808 $cleaned_subquery = $this->sanitize_query( $query ); |
|
809 |
|
810 if ( ! empty( $cleaned_subquery ) ) { |
|
811 // All queries with children must have a relation. |
|
812 if ( ! isset( $cleaned_subquery['relation'] ) ) { |
|
813 $cleaned_subquery['relation'] = 'AND'; |
|
814 } |
|
815 |
|
816 $cleaned_query[] = $cleaned_subquery; |
|
817 } |
|
818 } |
|
819 } |
|
820 |
|
821 return $cleaned_query; |
|
822 } |
|
823 |
|
824 /** |
|
825 * Sanitize a 'relation' operator. |
|
826 * |
|
827 * @since 4.1.0 |
|
828 * @access public |
|
829 * |
|
830 * @param string $relation Raw relation key from the query argument. |
|
831 * @return string Sanitized relation ('AND' or 'OR'). |
|
832 */ |
|
833 public function sanitize_relation( $relation ) { |
|
834 if ( 'OR' === strtoupper( $relation ) ) { |
|
835 return 'OR'; |
|
836 } else { |
|
837 return 'AND'; |
|
838 } |
|
839 } |
|
840 |
|
841 /** |
|
842 * Determine whether a clause is first-order. |
|
843 * |
|
844 * A "first-order" clause is one that contains any of the first-order |
|
845 * clause keys ('terms', 'taxonomy', 'include_children', 'field', |
|
846 * 'operator'). An empty clause also counts as a first-order clause, |
|
847 * for backward compatibility. Any clause that doesn't meet this is |
|
848 * determined, by process of elimination, to be a higher-order query. |
|
849 * |
|
850 * @since 4.1.0 |
|
851 * @access protected |
|
852 * |
|
853 * @param array $query Tax query arguments. |
|
854 * @return bool Whether the query clause is a first-order clause. |
|
855 */ |
|
856 protected static function is_first_order_clause( $query ) { |
|
857 return is_array( $query ) && ( empty( $query ) || array_key_exists( 'terms', $query ) || array_key_exists( 'taxonomy', $query ) || array_key_exists( 'include_children', $query ) || array_key_exists( 'field', $query ) || array_key_exists( 'operator', $query ) ); |
710 } |
858 } |
711 |
859 |
712 /** |
860 /** |
713 * Generates SQL clauses to be appended to a main query. |
861 * Generates SQL clauses to be appended to a main query. |
714 * |
862 * |
715 * @since 3.1.0 |
863 * @since 3.1.0 |
716 * @access public |
864 * @access public |
717 * |
865 * |
718 * @param string $primary_table |
866 * @param string $primary_table Database table where the object being filtered is stored (eg wp_users). |
719 * @param string $primary_id_column |
867 * @param string $primary_id_column ID column for the filtered object in $primary_table. |
720 * @return array |
868 * @return array { |
|
869 * Array containing JOIN and WHERE SQL clauses to append to the main query. |
|
870 * |
|
871 * @type string $join SQL fragment to append to the main JOIN clause. |
|
872 * @type string $where SQL fragment to append to the main WHERE clause. |
|
873 * } |
721 */ |
874 */ |
722 public function get_sql( $primary_table, $primary_id_column ) { |
875 public function get_sql( $primary_table, $primary_id_column ) { |
|
876 $this->primary_table = $primary_table; |
|
877 $this->primary_id_column = $primary_id_column; |
|
878 |
|
879 return $this->get_sql_clauses(); |
|
880 } |
|
881 |
|
882 /** |
|
883 * Generate SQL clauses to be appended to a main query. |
|
884 * |
|
885 * Called by the public {@see WP_Tax_Query::get_sql()}, this method |
|
886 * is abstracted out to maintain parity with the other Query classes. |
|
887 * |
|
888 * @since 4.1.0 |
|
889 * @access protected |
|
890 * |
|
891 * @return array { |
|
892 * Array containing JOIN and WHERE SQL clauses to append to the main query. |
|
893 * |
|
894 * @type string $join SQL fragment to append to the main JOIN clause. |
|
895 * @type string $where SQL fragment to append to the main WHERE clause. |
|
896 * } |
|
897 */ |
|
898 protected function get_sql_clauses() { |
|
899 /* |
|
900 * $queries are passed by reference to get_sql_for_query() for recursion. |
|
901 * To keep $this->queries unaltered, pass a copy. |
|
902 */ |
|
903 $queries = $this->queries; |
|
904 $sql = $this->get_sql_for_query( $queries ); |
|
905 |
|
906 if ( ! empty( $sql['where'] ) ) { |
|
907 $sql['where'] = ' AND ' . $sql['where']; |
|
908 } |
|
909 |
|
910 return $sql; |
|
911 } |
|
912 |
|
913 /** |
|
914 * Generate SQL clauses for a single query array. |
|
915 * |
|
916 * If nested subqueries are found, this method recurses the tree to |
|
917 * produce the properly nested SQL. |
|
918 * |
|
919 * @since 4.1.0 |
|
920 * @access protected |
|
921 * |
|
922 * @param array $query Query to parse, passed by reference. |
|
923 * @param int $depth Optional. Number of tree levels deep we currently are. |
|
924 * Used to calculate indentation. Default 0. |
|
925 * @return array { |
|
926 * Array containing JOIN and WHERE SQL clauses to append to a single query array. |
|
927 * |
|
928 * @type string $join SQL fragment to append to the main JOIN clause. |
|
929 * @type string $where SQL fragment to append to the main WHERE clause. |
|
930 * } |
|
931 */ |
|
932 protected function get_sql_for_query( &$query, $depth = 0 ) { |
|
933 $sql_chunks = array( |
|
934 'join' => array(), |
|
935 'where' => array(), |
|
936 ); |
|
937 |
|
938 $sql = array( |
|
939 'join' => '', |
|
940 'where' => '', |
|
941 ); |
|
942 |
|
943 $indent = ''; |
|
944 for ( $i = 0; $i < $depth; $i++ ) { |
|
945 $indent .= " "; |
|
946 } |
|
947 |
|
948 foreach ( $query as $key => &$clause ) { |
|
949 if ( 'relation' === $key ) { |
|
950 $relation = $query['relation']; |
|
951 } elseif ( is_array( $clause ) ) { |
|
952 |
|
953 // This is a first-order clause. |
|
954 if ( $this->is_first_order_clause( $clause ) ) { |
|
955 $clause_sql = $this->get_sql_for_clause( $clause, $query ); |
|
956 |
|
957 $where_count = count( $clause_sql['where'] ); |
|
958 if ( ! $where_count ) { |
|
959 $sql_chunks['where'][] = ''; |
|
960 } elseif ( 1 === $where_count ) { |
|
961 $sql_chunks['where'][] = $clause_sql['where'][0]; |
|
962 } else { |
|
963 $sql_chunks['where'][] = '( ' . implode( ' AND ', $clause_sql['where'] ) . ' )'; |
|
964 } |
|
965 |
|
966 $sql_chunks['join'] = array_merge( $sql_chunks['join'], $clause_sql['join'] ); |
|
967 // This is a subquery, so we recurse. |
|
968 } else { |
|
969 $clause_sql = $this->get_sql_for_query( $clause, $depth + 1 ); |
|
970 |
|
971 $sql_chunks['where'][] = $clause_sql['where']; |
|
972 $sql_chunks['join'][] = $clause_sql['join']; |
|
973 } |
|
974 } |
|
975 } |
|
976 |
|
977 // Filter to remove empties. |
|
978 $sql_chunks['join'] = array_filter( $sql_chunks['join'] ); |
|
979 $sql_chunks['where'] = array_filter( $sql_chunks['where'] ); |
|
980 |
|
981 if ( empty( $relation ) ) { |
|
982 $relation = 'AND'; |
|
983 } |
|
984 |
|
985 // Filter duplicate JOIN clauses and combine into a single string. |
|
986 if ( ! empty( $sql_chunks['join'] ) ) { |
|
987 $sql['join'] = implode( ' ', array_unique( $sql_chunks['join'] ) ); |
|
988 } |
|
989 |
|
990 // Generate a single WHERE clause with proper brackets and indentation. |
|
991 if ( ! empty( $sql_chunks['where'] ) ) { |
|
992 $sql['where'] = '( ' . "\n " . $indent . implode( ' ' . "\n " . $indent . $relation . ' ' . "\n " . $indent, $sql_chunks['where'] ) . "\n" . $indent . ')'; |
|
993 } |
|
994 |
|
995 return $sql; |
|
996 } |
|
997 |
|
998 /** |
|
999 * Generate SQL JOIN and WHERE clauses for a "first-order" query clause. |
|
1000 * |
|
1001 * @since 4.1.0 |
|
1002 * @access public |
|
1003 * |
|
1004 * @param array $clause Query clause, passed by reference |
|
1005 * @param array $parent_query Parent query array. |
|
1006 * @return array { |
|
1007 * Array containing JOIN and WHERE SQL clauses to append to a first-order query. |
|
1008 * |
|
1009 * @type string $join SQL fragment to append to the main JOIN clause. |
|
1010 * @type string $where SQL fragment to append to the main WHERE clause. |
|
1011 * } |
|
1012 */ |
|
1013 public function get_sql_for_clause( &$clause, $parent_query ) { |
723 global $wpdb; |
1014 global $wpdb; |
724 |
1015 |
|
1016 $sql = array( |
|
1017 'where' => array(), |
|
1018 'join' => array(), |
|
1019 ); |
|
1020 |
725 $join = ''; |
1021 $join = ''; |
726 $where = array(); |
1022 |
727 $i = 0; |
1023 $this->clean_query( $clause ); |
728 $count = count( $this->queries ); |
1024 |
729 |
1025 if ( is_wp_error( $clause ) ) { |
730 foreach ( $this->queries as $index => $query ) { |
1026 return self::$no_results; |
731 $this->clean_query( $query ); |
1027 } |
732 |
1028 |
733 if ( is_wp_error( $query ) ) |
1029 $terms = $clause['terms']; |
|
1030 $operator = strtoupper( $clause['operator'] ); |
|
1031 |
|
1032 if ( 'IN' == $operator ) { |
|
1033 |
|
1034 if ( empty( $terms ) ) { |
734 return self::$no_results; |
1035 return self::$no_results; |
735 |
1036 } |
736 extract( $query ); |
1037 |
737 |
1038 $terms = implode( ',', $terms ); |
738 if ( 'IN' == $operator ) { |
1039 |
739 |
1040 /* |
740 if ( empty( $terms ) ) { |
1041 * Before creating another table join, see if this clause has a |
741 if ( 'OR' == $this->relation ) { |
1042 * sibling with an existing join that can be shared. |
742 if ( ( $index + 1 === $count ) && empty( $where ) ) |
1043 */ |
743 return self::$no_results; |
1044 $alias = $this->find_compatible_table_alias( $clause, $parent_query ); |
744 continue; |
1045 if ( false === $alias ) { |
745 } else { |
1046 $i = count( $this->table_aliases ); |
746 return self::$no_results; |
|
747 } |
|
748 } |
|
749 |
|
750 $terms = implode( ',', $terms ); |
|
751 |
|
752 $alias = $i ? 'tt' . $i : $wpdb->term_relationships; |
1047 $alias = $i ? 'tt' . $i : $wpdb->term_relationships; |
|
1048 |
|
1049 // Store the alias as part of a flat array to build future iterators. |
|
1050 $this->table_aliases[] = $alias; |
|
1051 |
|
1052 // Store the alias with this clause, so later siblings can use it. |
|
1053 $clause['alias'] = $alias; |
753 |
1054 |
754 $join .= " INNER JOIN $wpdb->term_relationships"; |
1055 $join .= " INNER JOIN $wpdb->term_relationships"; |
755 $join .= $i ? " AS $alias" : ''; |
1056 $join .= $i ? " AS $alias" : ''; |
756 $join .= " ON ($primary_table.$primary_id_column = $alias.object_id)"; |
1057 $join .= " ON ($this->primary_table.$this->primary_id_column = $alias.object_id)"; |
757 |
|
758 $where[] = "$alias.term_taxonomy_id $operator ($terms)"; |
|
759 } elseif ( 'NOT IN' == $operator ) { |
|
760 |
|
761 if ( empty( $terms ) ) |
|
762 continue; |
|
763 |
|
764 $terms = implode( ',', $terms ); |
|
765 |
|
766 $where[] = "$primary_table.$primary_id_column NOT IN ( |
|
767 SELECT object_id |
|
768 FROM $wpdb->term_relationships |
|
769 WHERE term_taxonomy_id IN ($terms) |
|
770 )"; |
|
771 } elseif ( 'AND' == $operator ) { |
|
772 |
|
773 if ( empty( $terms ) ) |
|
774 continue; |
|
775 |
|
776 $num_terms = count( $terms ); |
|
777 |
|
778 $terms = implode( ',', $terms ); |
|
779 |
|
780 $where[] = "( |
|
781 SELECT COUNT(1) |
|
782 FROM $wpdb->term_relationships |
|
783 WHERE term_taxonomy_id IN ($terms) |
|
784 AND object_id = $primary_table.$primary_id_column |
|
785 ) = $num_terms"; |
|
786 } |
1058 } |
787 |
1059 |
788 $i++; |
1060 |
789 } |
1061 $where = "$alias.term_taxonomy_id $operator ($terms)"; |
790 |
1062 |
791 if ( ! empty( $where ) ) |
1063 } elseif ( 'NOT IN' == $operator ) { |
792 $where = ' AND ( ' . implode( " $this->relation ", $where ) . ' )'; |
1064 |
793 else |
1065 if ( empty( $terms ) ) { |
794 $where = ''; |
1066 return $sql; |
795 |
1067 } |
796 return compact( 'join', 'where' ); |
1068 |
|
1069 $terms = implode( ',', $terms ); |
|
1070 |
|
1071 $where = "$this->primary_table.$this->primary_id_column NOT IN ( |
|
1072 SELECT object_id |
|
1073 FROM $wpdb->term_relationships |
|
1074 WHERE term_taxonomy_id IN ($terms) |
|
1075 )"; |
|
1076 |
|
1077 } elseif ( 'AND' == $operator ) { |
|
1078 |
|
1079 if ( empty( $terms ) ) { |
|
1080 return $sql; |
|
1081 } |
|
1082 |
|
1083 $num_terms = count( $terms ); |
|
1084 |
|
1085 $terms = implode( ',', $terms ); |
|
1086 |
|
1087 $where = "( |
|
1088 SELECT COUNT(1) |
|
1089 FROM $wpdb->term_relationships |
|
1090 WHERE term_taxonomy_id IN ($terms) |
|
1091 AND object_id = $this->primary_table.$this->primary_id_column |
|
1092 ) = $num_terms"; |
|
1093 |
|
1094 } elseif ( 'NOT EXISTS' === $operator || 'EXISTS' === $operator ) { |
|
1095 |
|
1096 $where = $wpdb->prepare( "$operator ( |
|
1097 SELECT 1 |
|
1098 FROM $wpdb->term_relationships |
|
1099 INNER JOIN $wpdb->term_taxonomy |
|
1100 ON $wpdb->term_taxonomy.term_taxonomy_id = $wpdb->term_relationships.term_taxonomy_id |
|
1101 WHERE $wpdb->term_taxonomy.taxonomy = %s |
|
1102 AND $wpdb->term_relationships.object_id = $this->primary_table.$this->primary_id_column |
|
1103 )", $clause['taxonomy'] ); |
|
1104 |
|
1105 } |
|
1106 |
|
1107 $sql['join'][] = $join; |
|
1108 $sql['where'][] = $where; |
|
1109 return $sql; |
|
1110 } |
|
1111 |
|
1112 /** |
|
1113 * Identify an existing table alias that is compatible with the current query clause. |
|
1114 * |
|
1115 * We avoid unnecessary table joins by allowing each clause to look for |
|
1116 * an existing table alias that is compatible with the query that it |
|
1117 * needs to perform. |
|
1118 * |
|
1119 * An existing alias is compatible if (a) it is a sibling of `$clause` |
|
1120 * (ie, it's under the scope of the same relation), and (b) the combination |
|
1121 * of operator and relation between the clauses allows for a shared table |
|
1122 * join. In the case of {@see WP_Tax_Query}, this only applies to 'IN' |
|
1123 * clauses that are connected by the relation 'OR'. |
|
1124 * |
|
1125 * @since 4.1.0 |
|
1126 * @access protected |
|
1127 * |
|
1128 * @param array $clause Query clause. |
|
1129 * @param array $parent_query Parent query of $clause. |
|
1130 * @return string|bool Table alias if found, otherwise false. |
|
1131 */ |
|
1132 protected function find_compatible_table_alias( $clause, $parent_query ) { |
|
1133 $alias = false; |
|
1134 |
|
1135 // Sanity check. Only IN queries use the JOIN syntax . |
|
1136 if ( ! isset( $clause['operator'] ) || 'IN' !== $clause['operator'] ) { |
|
1137 return $alias; |
|
1138 } |
|
1139 |
|
1140 // Since we're only checking IN queries, we're only concerned with OR relations. |
|
1141 if ( ! isset( $parent_query['relation'] ) || 'OR' !== $parent_query['relation'] ) { |
|
1142 return $alias; |
|
1143 } |
|
1144 |
|
1145 $compatible_operators = array( 'IN' ); |
|
1146 |
|
1147 foreach ( $parent_query as $sibling ) { |
|
1148 if ( ! is_array( $sibling ) || ! $this->is_first_order_clause( $sibling ) ) { |
|
1149 continue; |
|
1150 } |
|
1151 |
|
1152 if ( empty( $sibling['alias'] ) || empty( $sibling['operator'] ) ) { |
|
1153 continue; |
|
1154 } |
|
1155 |
|
1156 // The sibling must both have compatible operator to share its alias. |
|
1157 if ( in_array( strtoupper( $sibling['operator'] ), $compatible_operators ) ) { |
|
1158 $alias = $sibling['alias']; |
|
1159 break; |
|
1160 } |
|
1161 } |
|
1162 |
|
1163 return $alias; |
797 } |
1164 } |
798 |
1165 |
799 /** |
1166 /** |
800 * Validates a single query. |
1167 * Validates a single query. |
801 * |
1168 * |
802 * @since 3.2.0 |
1169 * @since 3.2.0 |
803 * @access private |
1170 * @access private |
804 * |
1171 * |
805 * @param array &$query The single query |
1172 * @param array &$query The single query. |
806 */ |
1173 */ |
807 private function clean_query( &$query ) { |
1174 private function clean_query( &$query ) { |
808 if ( ! taxonomy_exists( $query['taxonomy'] ) ) { |
1175 if ( empty( $query['taxonomy'] ) ) { |
|
1176 if ( 'term_taxonomy_id' !== $query['field'] ) { |
|
1177 $query = new WP_Error( 'Invalid taxonomy' ); |
|
1178 return; |
|
1179 } |
|
1180 |
|
1181 // so long as there are shared terms, include_children requires that a taxonomy is set |
|
1182 $query['include_children'] = false; |
|
1183 } elseif ( ! taxonomy_exists( $query['taxonomy'] ) ) { |
809 $query = new WP_Error( 'Invalid taxonomy' ); |
1184 $query = new WP_Error( 'Invalid taxonomy' ); |
810 return; |
1185 return; |
811 } |
1186 } |
812 |
1187 |
813 $query['terms'] = array_unique( (array) $query['terms'] ); |
1188 $query['terms'] = array_unique( (array) $query['terms'] ); |
1166 * the $args. |
1561 * the $args. |
1167 * |
1562 * |
1168 * The 'get_terms_orderby' filter passes the ORDER BY clause for the query |
1563 * The 'get_terms_orderby' filter passes the ORDER BY clause for the query |
1169 * along with the $args array. |
1564 * along with the $args array. |
1170 * |
1565 * |
1171 * The 'get_terms_fields' filter passes the fields for the SELECT query |
|
1172 * along with the $args array. |
|
1173 * |
|
1174 * The list of arguments that $args can contain, which will overwrite the defaults: |
|
1175 * |
|
1176 * orderby - Default is 'name'. Can be name, count, term_group, slug or nothing |
|
1177 * (will use term_id), Passing a custom value other than these will cause it to |
|
1178 * order based on the custom value. |
|
1179 * |
|
1180 * order - Default is ASC. Can use DESC. |
|
1181 * |
|
1182 * hide_empty - Default is true. Will not return empty terms, which means |
|
1183 * terms whose count is 0 according to the given taxonomy. |
|
1184 * |
|
1185 * exclude - Default is an empty array. An array, comma- or space-delimited string |
|
1186 * of term ids to exclude from the return array. If 'include' is non-empty, |
|
1187 * 'exclude' is ignored. |
|
1188 * |
|
1189 * exclude_tree - Default is an empty array. An array, comma- or space-delimited |
|
1190 * string of term ids to exclude from the return array, along with all of their |
|
1191 * descendant terms according to the primary taxonomy. If 'include' is non-empty, |
|
1192 * 'exclude_tree' is ignored. |
|
1193 * |
|
1194 * include - Default is an empty array. An array, comma- or space-delimited string |
|
1195 * of term ids to include in the return array. |
|
1196 * |
|
1197 * number - The maximum number of terms to return. Default is to return them all. |
|
1198 * |
|
1199 * offset - The number by which to offset the terms query. |
|
1200 * |
|
1201 * fields - Default is 'all', which returns an array of term objects. |
|
1202 * If 'fields' is 'ids' or 'names', returns an array of |
|
1203 * integers or strings, respectively. |
|
1204 * |
|
1205 * slug - Returns terms whose "slug" matches this value. Default is empty string. |
|
1206 * |
|
1207 * hierarchical - Whether to include terms that have non-empty descendants |
|
1208 * (even if 'hide_empty' is set to true). |
|
1209 * |
|
1210 * search - Returned terms' names will contain the value of 'search', |
|
1211 * case-insensitive. Default is an empty string. |
|
1212 * |
|
1213 * name__like - Returned terms' names will contain the value of 'name__like', |
|
1214 * case-insensitive. Default is empty string. |
|
1215 * |
|
1216 * description__like - Returned terms' descriptions will contain the value of |
|
1217 * 'description__like', case-insensitive. Default is empty string. |
|
1218 * |
|
1219 * The argument 'pad_counts', if set to true will include the quantity of a term's |
|
1220 * children in the quantity of each term's "count" object variable. |
|
1221 * |
|
1222 * The 'get' argument, if set to 'all' instead of its default empty string, |
|
1223 * returns terms regardless of ancestry or whether the terms are empty. |
|
1224 * |
|
1225 * The 'child_of' argument, when used, should be set to the integer of a term ID. Its default |
|
1226 * is 0. If set to a non-zero value, all returned terms will be descendants |
|
1227 * of that term according to the given taxonomy. Hence 'child_of' is set to 0 |
|
1228 * if more than one taxonomy is passed in $taxonomies, because multiple taxonomies |
|
1229 * make term ancestry ambiguous. |
|
1230 * |
|
1231 * The 'parent' argument, when used, should be set to the integer of a term ID. Its default is |
|
1232 * the empty string '', which has a different meaning from the integer 0. |
|
1233 * If set to an integer value, all returned terms will have as an immediate |
|
1234 * ancestor the term whose ID is specified by that integer according to the given taxonomy. |
|
1235 * The 'parent' argument is different from 'child_of' in that a term X is considered a 'parent' |
|
1236 * of term Y only if term X is the father of term Y, not its grandfather or great-grandfather, etc. |
|
1237 * |
|
1238 * The 'cache_domain' argument enables a unique cache key to be produced when this query is stored |
|
1239 * in object cache. For instance, if you are using one of this function's filters to modify the |
|
1240 * query (such as 'terms_clauses'), setting 'cache_domain' to a unique value will not overwrite |
|
1241 * the cache for similar queries. Default value is 'core'. |
|
1242 * |
|
1243 * @package WordPress |
|
1244 * @subpackage Taxonomy |
|
1245 * @since 2.3.0 |
1566 * @since 2.3.0 |
1246 * |
1567 * @since 4.2.0 Introduced 'name' and 'childless' parameters. |
1247 * @uses $wpdb |
1568 * |
1248 * @uses wp_parse_args() Merges the defaults with those defined by $args and allows for strings. |
1569 * @global wpdb $wpdb WordPress database abstraction object. |
1249 * |
1570 * |
1250 * @param string|array $taxonomies Taxonomy name or list of Taxonomy names |
1571 * @param string|array $taxonomies Taxonomy name or list of Taxonomy names. |
1251 * @param string|array $args The values of what to search for when returning terms |
1572 * @param array|string $args { |
1252 * @return array|WP_Error List of Term Objects and their children. Will return WP_Error, if any of $taxonomies do not exist. |
1573 * Optional. Array or string of arguments to get terms. |
1253 */ |
1574 * |
1254 function get_terms($taxonomies, $args = '') { |
1575 * @type string $orderby Field(s) to order terms by. Accepts term fields ('name', 'slug', |
|
1576 * 'term_group', 'term_id', 'id', 'description'), 'count' for term |
|
1577 * taxonomy count, 'include' to match the 'order' of the $include param, |
|
1578 * or 'none' to skip ORDER BY. Defaults to 'name'. |
|
1579 * @type string $order Whether to order terms in ascending or descending order. |
|
1580 * Accepts 'ASC' (ascending) or 'DESC' (descending). |
|
1581 * Default 'ASC'. |
|
1582 * @type bool|int $hide_empty Whether to hide terms not assigned to any posts. Accepts |
|
1583 * 1|true or 0|false. Default 1|true. |
|
1584 * @type array|string $include Array or comma/space-separated string of term ids to include. |
|
1585 * Default empty array. |
|
1586 * @type array|string $exclude Array or comma/space-separated string of term ids to exclude. |
|
1587 * If $include is non-empty, $exclude is ignored. |
|
1588 * Default empty array. |
|
1589 * @type array|string $exclude_tree Array or comma/space-separated string of term ids to exclude |
|
1590 * along with all of their descendant terms. If $include is |
|
1591 * non-empty, $exclude_tree is ignored. Default empty array. |
|
1592 * @type int|string $number Maximum number of terms to return. Accepts ''|0 (all) or any |
|
1593 * positive number. Default ''|0 (all). |
|
1594 * @type int $offset The number by which to offset the terms query. Default empty. |
|
1595 * @type string $fields Term fields to query for. Accepts 'all' (returns an array of |
|
1596 * term objects), 'ids' or 'names' (returns an array of integers |
|
1597 * or strings, respectively. Default 'all'. |
|
1598 * @type string|array $name Optional. Name or array of names to return term(s) for. Default empty. |
|
1599 * @type string|array $slug Optional. Slug or array of slugs to return term(s) for. Default empty. |
|
1600 * @type bool $hierarchical Whether to include terms that have non-empty descendants (even |
|
1601 * if $hide_empty is set to true). Default true. |
|
1602 * @type string $search Search criteria to match terms. Will be SQL-formatted with |
|
1603 * wildcards before and after. Default empty. |
|
1604 * @type string $name__like Retrieve terms with criteria by which a term is LIKE $name__like. |
|
1605 * Default empty. |
|
1606 * @type string $description__like Retrieve terms where the description is LIKE $description__like. |
|
1607 * Default empty. |
|
1608 * @type bool $pad_counts Whether to pad the quantity of a term's children in the quantity |
|
1609 * of each term's "count" object variable. Default false. |
|
1610 * @type string $get Whether to return terms regardless of ancestry or whether the terms |
|
1611 * are empty. Accepts 'all' or empty (disabled). Default empty. |
|
1612 * @type int $child_of Term ID to retrieve child terms of. If multiple taxonomies |
|
1613 * are passed, $child_of is ignored. Default 0. |
|
1614 * @type int|string $parent Parent term ID to retrieve direct-child terms of. Default empty. |
|
1615 * @type bool $childless True to limit results to terms that have no children. This parameter has |
|
1616 * no effect on non-hierarchical taxonomies. Default false. |
|
1617 * @type string $cache_domain Unique cache key to be produced when this query is stored in an |
|
1618 * object cache. Default is 'core'. |
|
1619 * } |
|
1620 * @return array|WP_Error List of Term Objects and their children. Will return WP_Error, if any of $taxonomies |
|
1621 * do not exist. |
|
1622 */ |
|
1623 function get_terms( $taxonomies, $args = '' ) { |
1255 global $wpdb; |
1624 global $wpdb; |
1256 $empty_array = array(); |
1625 $empty_array = array(); |
1257 |
1626 |
1258 $single_taxonomy = ! is_array( $taxonomies ) || 1 === count( $taxonomies ); |
1627 $single_taxonomy = ! is_array( $taxonomies ) || 1 === count( $taxonomies ); |
1259 if ( ! is_array( $taxonomies ) ) |
1628 if ( ! is_array( $taxonomies ) ) { |
1260 $taxonomies = array( $taxonomies ); |
1629 $taxonomies = array( $taxonomies ); |
|
1630 } |
1261 |
1631 |
1262 foreach ( $taxonomies as $taxonomy ) { |
1632 foreach ( $taxonomies as $taxonomy ) { |
1263 if ( ! taxonomy_exists($taxonomy) ) { |
1633 if ( ! taxonomy_exists($taxonomy) ) { |
1264 $error = new WP_Error('invalid_taxonomy', __('Invalid taxonomy')); |
1634 $error = new WP_Error('invalid_taxonomy', __('Invalid taxonomy')); |
1265 return $error; |
1635 return $error; |
1266 } |
1636 } |
1267 } |
1637 } |
1268 |
1638 |
1269 $defaults = array('orderby' => 'name', 'order' => 'ASC', |
1639 $defaults = array('orderby' => 'name', 'order' => 'ASC', |
1270 'hide_empty' => true, 'exclude' => array(), 'exclude_tree' => array(), 'include' => array(), |
1640 'hide_empty' => true, 'exclude' => array(), 'exclude_tree' => array(), 'include' => array(), |
1271 'number' => '', 'fields' => 'all', 'slug' => '', 'parent' => '', |
1641 'number' => '', 'fields' => 'all', 'name' => '', 'slug' => '', 'parent' => '', 'childless' => false, |
1272 'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '', 'description__like' => '', |
1642 'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '', 'description__like' => '', |
1273 'pad_counts' => false, 'offset' => '', 'search' => '', 'cache_domain' => 'core' ); |
1643 'pad_counts' => false, 'offset' => '', 'search' => '', 'cache_domain' => 'core' ); |
1274 $args = wp_parse_args( $args, $defaults ); |
1644 $args = wp_parse_args( $args, $defaults ); |
1275 $args['number'] = absint( $args['number'] ); |
1645 $args['number'] = absint( $args['number'] ); |
1276 $args['offset'] = absint( $args['offset'] ); |
1646 $args['offset'] = absint( $args['offset'] ); |
1277 if ( !$single_taxonomy || ! is_taxonomy_hierarchical( reset( $taxonomies ) ) || |
1647 |
1278 '' !== $args['parent'] ) { |
1648 // Save queries by not crawling the tree in the case of multiple taxes or a flat tax. |
1279 $args['child_of'] = 0; |
1649 $has_hierarchical_tax = false; |
|
1650 foreach ( $taxonomies as $_tax ) { |
|
1651 if ( is_taxonomy_hierarchical( $_tax ) ) { |
|
1652 $has_hierarchical_tax = true; |
|
1653 } |
|
1654 } |
|
1655 |
|
1656 if ( ! $has_hierarchical_tax ) { |
1280 $args['hierarchical'] = false; |
1657 $args['hierarchical'] = false; |
1281 $args['pad_counts'] = false; |
1658 $args['pad_counts'] = false; |
1282 } |
1659 } |
1283 |
1660 |
|
1661 // 'parent' overrides 'child_of'. |
|
1662 if ( 0 < intval( $args['parent'] ) ) { |
|
1663 $args['child_of'] = false; |
|
1664 } |
|
1665 |
1284 if ( 'all' == $args['get'] ) { |
1666 if ( 'all' == $args['get'] ) { |
|
1667 $args['childless'] = false; |
1285 $args['child_of'] = 0; |
1668 $args['child_of'] = 0; |
1286 $args['hide_empty'] = 0; |
1669 $args['hide_empty'] = 0; |
1287 $args['hierarchical'] = false; |
1670 $args['hierarchical'] = false; |
1288 $args['pad_counts'] = false; |
1671 $args['pad_counts'] = false; |
1289 } |
1672 } |
1290 |
1673 |
|
1674 /** |
|
1675 * Filter the terms query arguments. |
|
1676 * |
|
1677 * @since 3.1.0 |
|
1678 * |
|
1679 * @param array $args An array of arguments. |
|
1680 * @param array $taxonomies An array of taxonomies. |
|
1681 */ |
1291 $args = apply_filters( 'get_terms_args', $args, $taxonomies ); |
1682 $args = apply_filters( 'get_terms_args', $args, $taxonomies ); |
1292 |
1683 |
1293 extract($args, EXTR_SKIP); |
1684 // Avoid the query if the queried parent/child_of term has no descendants. |
|
1685 $child_of = $args['child_of']; |
|
1686 $parent = $args['parent']; |
1294 |
1687 |
1295 if ( $child_of ) { |
1688 if ( $child_of ) { |
1296 $hierarchy = _get_term_hierarchy( reset( $taxonomies ) ); |
1689 $_parent = $child_of; |
1297 if ( ! isset( $hierarchy[ $child_of ] ) ) |
1690 } elseif ( $parent ) { |
|
1691 $_parent = $parent; |
|
1692 } else { |
|
1693 $_parent = false; |
|
1694 } |
|
1695 |
|
1696 if ( $_parent ) { |
|
1697 $in_hierarchy = false; |
|
1698 foreach ( $taxonomies as $_tax ) { |
|
1699 $hierarchy = _get_term_hierarchy( $_tax ); |
|
1700 |
|
1701 if ( isset( $hierarchy[ $_parent ] ) ) { |
|
1702 $in_hierarchy = true; |
|
1703 } |
|
1704 } |
|
1705 |
|
1706 if ( ! $in_hierarchy ) { |
1298 return $empty_array; |
1707 return $empty_array; |
1299 } |
1708 } |
1300 |
|
1301 if ( $parent ) { |
|
1302 $hierarchy = _get_term_hierarchy( reset( $taxonomies ) ); |
|
1303 if ( ! isset( $hierarchy[ $parent ] ) ) |
|
1304 return $empty_array; |
|
1305 } |
1709 } |
1306 |
1710 |
1307 // $args can be whatever, only use the args defined in defaults to compute the key |
1711 // $args can be whatever, only use the args defined in defaults to compute the key |
1308 $filter_key = ( has_filter('list_terms_exclusions') ) ? serialize($GLOBALS['wp_filter']['list_terms_exclusions']) : ''; |
1712 $filter_key = ( has_filter('list_terms_exclusions') ) ? serialize($GLOBALS['wp_filter']['list_terms_exclusions']) : ''; |
1309 $key = md5( serialize( compact(array_keys($defaults)) ) . serialize( $taxonomies ) . $filter_key ); |
1713 $key = md5( serialize( wp_array_slice_assoc( $args, array_keys( $defaults ) ) ) . serialize( $taxonomies ) . $filter_key ); |
1310 $last_changed = wp_cache_get( 'last_changed', 'terms' ); |
1714 $last_changed = wp_cache_get( 'last_changed', 'terms' ); |
1311 if ( ! $last_changed ) { |
1715 if ( ! $last_changed ) { |
1312 $last_changed = microtime(); |
1716 $last_changed = microtime(); |
1313 wp_cache_set( 'last_changed', $last_changed, 'terms' ); |
1717 wp_cache_set( 'last_changed', $last_changed, 'terms' ); |
1314 } |
1718 } |
1315 $cache_key = "get_terms:$key:$last_changed"; |
1719 $cache_key = "get_terms:$key:$last_changed"; |
1316 $cache = wp_cache_get( $cache_key, 'terms' ); |
1720 $cache = wp_cache_get( $cache_key, 'terms' ); |
1317 if ( false !== $cache ) { |
1721 if ( false !== $cache ) { |
1318 $cache = apply_filters('get_terms', $cache, $taxonomies, $args); |
1722 |
|
1723 /** |
|
1724 * Filter the given taxonomy's terms cache. |
|
1725 * |
|
1726 * @since 2.3.0 |
|
1727 * |
|
1728 * @param array $cache Cached array of terms for the given taxonomy. |
|
1729 * @param array $taxonomies An array of taxonomies. |
|
1730 * @param array $args An array of arguments to get terms. |
|
1731 */ |
|
1732 $cache = apply_filters( 'get_terms', $cache, $taxonomies, $args ); |
1319 return $cache; |
1733 return $cache; |
1320 } |
1734 } |
1321 |
1735 |
1322 $_orderby = strtolower($orderby); |
1736 $_orderby = strtolower( $args['orderby'] ); |
1323 if ( 'count' == $_orderby ) |
1737 if ( 'count' == $_orderby ) { |
1324 $orderby = 'tt.count'; |
1738 $orderby = 'tt.count'; |
1325 else if ( 'name' == $_orderby ) |
1739 } elseif ( 'name' == $_orderby ) { |
1326 $orderby = 't.name'; |
1740 $orderby = 't.name'; |
1327 else if ( 'slug' == $_orderby ) |
1741 } elseif ( 'slug' == $_orderby ) { |
1328 $orderby = 't.slug'; |
1742 $orderby = 't.slug'; |
1329 else if ( 'term_group' == $_orderby ) |
1743 } elseif ( 'include' == $_orderby && ! empty( $args['include'] ) ) { |
|
1744 $include = implode( ',', array_map( 'absint', $args['include'] ) ); |
|
1745 $orderby = "FIELD( t.term_id, $include )"; |
|
1746 } elseif ( 'term_group' == $_orderby ) { |
1330 $orderby = 't.term_group'; |
1747 $orderby = 't.term_group'; |
1331 else if ( 'none' == $_orderby ) |
1748 } elseif ( 'description' == $_orderby ) { |
|
1749 $orderby = 'tt.description'; |
|
1750 } elseif ( 'none' == $_orderby ) { |
1332 $orderby = ''; |
1751 $orderby = ''; |
1333 elseif ( empty($_orderby) || 'id' == $_orderby ) |
1752 } elseif ( empty($_orderby) || 'id' == $_orderby ) { |
1334 $orderby = 't.term_id'; |
1753 $orderby = 't.term_id'; |
1335 else |
1754 } else { |
1336 $orderby = 't.name'; |
1755 $orderby = 't.name'; |
1337 |
1756 } |
|
1757 /** |
|
1758 * Filter the ORDERBY clause of the terms query. |
|
1759 * |
|
1760 * @since 2.8.0 |
|
1761 * |
|
1762 * @param string $orderby ORDERBY clause of the terms query. |
|
1763 * @param array $args An array of terms query arguments. |
|
1764 * @param array $taxonomies An array of taxonomies. |
|
1765 */ |
1338 $orderby = apply_filters( 'get_terms_orderby', $orderby, $args, $taxonomies ); |
1766 $orderby = apply_filters( 'get_terms_orderby', $orderby, $args, $taxonomies ); |
1339 |
1767 |
1340 if ( !empty($orderby) ) |
1768 $order = strtoupper( $args['order'] ); |
|
1769 if ( ! empty( $orderby ) ) { |
1341 $orderby = "ORDER BY $orderby"; |
1770 $orderby = "ORDER BY $orderby"; |
1342 else |
1771 } else { |
1343 $order = ''; |
1772 $order = ''; |
1344 |
1773 } |
1345 $order = strtoupper( $order ); |
1774 |
1346 if ( '' !== $order && !in_array( $order, array( 'ASC', 'DESC' ) ) ) |
1775 if ( '' !== $order && ! in_array( $order, array( 'ASC', 'DESC' ) ) ) { |
1347 $order = 'ASC'; |
1776 $order = 'ASC'; |
|
1777 } |
1348 |
1778 |
1349 $where = "tt.taxonomy IN ('" . implode("', '", $taxonomies) . "')"; |
1779 $where = "tt.taxonomy IN ('" . implode("', '", $taxonomies) . "')"; |
|
1780 |
|
1781 $exclude = $args['exclude']; |
|
1782 $exclude_tree = $args['exclude_tree']; |
|
1783 $include = $args['include']; |
|
1784 |
1350 $inclusions = ''; |
1785 $inclusions = ''; |
1351 if ( ! empty( $include ) ) { |
1786 if ( ! empty( $include ) ) { |
1352 $exclude = ''; |
1787 $exclude = ''; |
1353 $exclude_tree = ''; |
1788 $exclude_tree = ''; |
1354 $inclusions = implode( ',', wp_parse_id_list( $include ) ); |
1789 $inclusions = implode( ',', wp_parse_id_list( $include ) ); |
1357 if ( ! empty( $inclusions ) ) { |
1792 if ( ! empty( $inclusions ) ) { |
1358 $inclusions = ' AND t.term_id IN ( ' . $inclusions . ' )'; |
1793 $inclusions = ' AND t.term_id IN ( ' . $inclusions . ' )'; |
1359 $where .= $inclusions; |
1794 $where .= $inclusions; |
1360 } |
1795 } |
1361 |
1796 |
1362 $exclusions = ''; |
1797 $exclusions = array(); |
1363 if ( ! empty( $exclude_tree ) ) { |
1798 if ( ! empty( $exclude_tree ) ) { |
1364 $exclude_tree = wp_parse_id_list( $exclude_tree ); |
1799 $exclude_tree = wp_parse_id_list( $exclude_tree ); |
1365 $excluded_children = $exclude_tree; |
1800 $excluded_children = $exclude_tree; |
1366 foreach ( $exclude_tree as $extrunk ) { |
1801 foreach ( $exclude_tree as $extrunk ) { |
1367 $excluded_children = array_merge( |
1802 $excluded_children = array_merge( |
1368 $excluded_children, |
1803 $excluded_children, |
1369 (array) get_terms( $taxonomies[0], array( 'child_of' => intval( $extrunk ), 'fields' => 'ids', 'hide_empty' => 0 ) ) |
1804 (array) get_terms( $taxonomies[0], array( 'child_of' => intval( $extrunk ), 'fields' => 'ids', 'hide_empty' => 0 ) ) |
1370 ); |
1805 ); |
1371 } |
1806 } |
1372 $exclusions = implode( ',', array_map( 'intval', $excluded_children ) ); |
1807 $exclusions = array_merge( $excluded_children, $exclusions ); |
1373 } |
1808 } |
1374 |
1809 |
1375 if ( ! empty( $exclude ) ) { |
1810 if ( ! empty( $exclude ) ) { |
1376 $exterms = wp_parse_id_list( $exclude ); |
1811 $exclusions = array_merge( wp_parse_id_list( $exclude ), $exclusions ); |
1377 if ( empty( $exclusions ) ) |
1812 } |
1378 $exclusions = implode( ',', $exterms ); |
1813 |
1379 else |
1814 // 'childless' terms are those without an entry in the flattened term hierarchy. |
1380 $exclusions .= ', ' . implode( ',', $exterms ); |
1815 $childless = (bool) $args['childless']; |
1381 } |
1816 if ( $childless ) { |
1382 |
1817 foreach ( $taxonomies as $_tax ) { |
1383 if ( ! empty( $exclusions ) ) |
1818 $term_hierarchy = _get_term_hierarchy( $_tax ); |
1384 $exclusions = ' AND t.term_id NOT IN (' . $exclusions . ')'; |
1819 $exclusions = array_merge( array_keys( $term_hierarchy ), $exclusions ); |
1385 |
1820 } |
|
1821 } |
|
1822 |
|
1823 if ( ! empty( $exclusions ) ) { |
|
1824 $exclusions = ' AND t.term_id NOT IN (' . implode( ',', array_map( 'intval', $exclusions ) ) . ')'; |
|
1825 } else { |
|
1826 $exclusions = ''; |
|
1827 } |
|
1828 |
|
1829 /** |
|
1830 * Filter the terms to exclude from the terms query. |
|
1831 * |
|
1832 * @since 2.3.0 |
|
1833 * |
|
1834 * @param string $exclusions NOT IN clause of the terms query. |
|
1835 * @param array $args An array of terms query arguments. |
|
1836 * @param array $taxonomies An array of taxonomies. |
|
1837 */ |
1386 $exclusions = apply_filters( 'list_terms_exclusions', $exclusions, $args, $taxonomies ); |
1838 $exclusions = apply_filters( 'list_terms_exclusions', $exclusions, $args, $taxonomies ); |
1387 |
1839 |
1388 if ( ! empty( $exclusions ) ) |
1840 if ( ! empty( $exclusions ) ) { |
1389 $where .= $exclusions; |
1841 $where .= $exclusions; |
1390 |
1842 } |
1391 if ( !empty($slug) ) { |
1843 |
1392 $slug = sanitize_title($slug); |
1844 if ( ! empty( $args['name'] ) ) { |
1393 $where .= " AND t.slug = '$slug'"; |
1845 if ( is_array( $args['name'] ) ) { |
1394 } |
1846 $name = array_map( 'sanitize_text_field', $args['name'] ); |
1395 |
1847 $where .= " AND t.name IN ('" . implode( "', '", array_map( 'esc_sql', $name ) ) . "')"; |
1396 if ( !empty($name__like) ) { |
1848 } else { |
1397 $name__like = like_escape( $name__like ); |
1849 $name = sanitize_text_field( $args['name'] ); |
1398 $where .= $wpdb->prepare( " AND t.name LIKE %s", '%' . $name__like . '%' ); |
1850 $where .= $wpdb->prepare( " AND t.name = %s", $name ); |
1399 } |
1851 } |
1400 |
1852 } |
1401 if ( ! empty( $description__like ) ) { |
1853 |
1402 $description__like = like_escape( $description__like ); |
1854 if ( ! empty( $args['slug'] ) ) { |
1403 $where .= $wpdb->prepare( " AND tt.description LIKE %s", '%' . $description__like . '%' ); |
1855 if ( is_array( $args['slug'] ) ) { |
|
1856 $slug = array_map( 'sanitize_title', $args['slug'] ); |
|
1857 $where .= " AND t.slug IN ('" . implode( "', '", $slug ) . "')"; |
|
1858 } else { |
|
1859 $slug = sanitize_title( $args['slug'] ); |
|
1860 $where .= " AND t.slug = '$slug'"; |
|
1861 } |
|
1862 } |
|
1863 |
|
1864 if ( ! empty( $args['name__like'] ) ) { |
|
1865 $where .= $wpdb->prepare( " AND t.name LIKE %s", '%' . $wpdb->esc_like( $args['name__like'] ) . '%' ); |
|
1866 } |
|
1867 |
|
1868 if ( ! empty( $args['description__like'] ) ) { |
|
1869 $where .= $wpdb->prepare( " AND tt.description LIKE %s", '%' . $wpdb->esc_like( $args['description__like'] ) . '%' ); |
1404 } |
1870 } |
1405 |
1871 |
1406 if ( '' !== $parent ) { |
1872 if ( '' !== $parent ) { |
1407 $parent = (int) $parent; |
1873 $parent = (int) $parent; |
1408 $where .= " AND tt.parent = '$parent'"; |
1874 $where .= " AND tt.parent = '$parent'"; |
1409 } |
1875 } |
1410 |
1876 |
1411 if ( 'count' == $fields ) |
1877 $hierarchical = $args['hierarchical']; |
|
1878 if ( 'count' == $args['fields'] ) { |
1412 $hierarchical = false; |
1879 $hierarchical = false; |
1413 |
1880 } |
1414 if ( $hide_empty && !$hierarchical ) |
1881 if ( $args['hide_empty'] && !$hierarchical ) { |
1415 $where .= ' AND tt.count > 0'; |
1882 $where .= ' AND tt.count > 0'; |
|
1883 } |
|
1884 |
|
1885 $number = $args['number']; |
|
1886 $offset = $args['offset']; |
1416 |
1887 |
1417 // don't limit the query results when we have to descend the family tree |
1888 // don't limit the query results when we have to descend the family tree |
1418 if ( $number && ! $hierarchical && ! $child_of && '' === $parent ) { |
1889 if ( $number && ! $hierarchical && ! $child_of && '' === $parent ) { |
1419 if ( $offset ) |
1890 if ( $offset ) { |
1420 $limits = 'LIMIT ' . $offset . ',' . $number; |
1891 $limits = 'LIMIT ' . $offset . ',' . $number; |
1421 else |
1892 } else { |
1422 $limits = 'LIMIT ' . $number; |
1893 $limits = 'LIMIT ' . $number; |
|
1894 } |
1423 } else { |
1895 } else { |
1424 $limits = ''; |
1896 $limits = ''; |
1425 } |
1897 } |
1426 |
1898 |
1427 if ( ! empty( $search ) ) { |
1899 if ( ! empty( $args['search'] ) ) { |
1428 $search = like_escape( $search ); |
1900 $like = '%' . $wpdb->esc_like( $args['search'] ) . '%'; |
1429 $where .= $wpdb->prepare( ' AND ((t.name LIKE %s) OR (t.slug LIKE %s))', '%' . $search . '%', '%' . $search . '%' ); |
1901 $where .= $wpdb->prepare( ' AND ((t.name LIKE %s) OR (t.slug LIKE %s))', $like, $like ); |
1430 } |
1902 } |
1431 |
1903 |
1432 $selects = array(); |
1904 $selects = array(); |
1433 switch ( $fields ) { |
1905 switch ( $args['fields'] ) { |
1434 case 'all': |
1906 case 'all': |
1435 $selects = array( 't.*', 'tt.*' ); |
1907 $selects = array( 't.*', 'tt.*' ); |
1436 break; |
1908 break; |
1437 case 'ids': |
1909 case 'ids': |
1438 case 'id=>parent': |
1910 case 'id=>parent': |
1439 $selects = array( 't.term_id', 'tt.parent', 'tt.count' ); |
1911 $selects = array( 't.term_id', 'tt.parent', 'tt.count', 'tt.taxonomy' ); |
1440 break; |
1912 break; |
1441 case 'names': |
1913 case 'names': |
1442 $selects = array( 't.term_id', 'tt.parent', 'tt.count', 't.name' ); |
1914 $selects = array( 't.term_id', 'tt.parent', 'tt.count', 't.name', 'tt.taxonomy' ); |
1443 break; |
1915 break; |
1444 case 'count': |
1916 case 'count': |
1445 $orderby = ''; |
1917 $orderby = ''; |
1446 $order = ''; |
1918 $order = ''; |
1447 $selects = array( 'COUNT(*)' ); |
1919 $selects = array( 'COUNT(*)' ); |
1448 break; |
1920 break; |
1449 case 'id=>name': |
1921 case 'id=>name': |
1450 $selects = array( 't.term_id', 't.name' ); |
1922 $selects = array( 't.term_id', 't.name', 'tt.count', 'tt.taxonomy' ); |
1451 break; |
1923 break; |
1452 case 'id=>slug': |
1924 case 'id=>slug': |
1453 $selects = array( 't.term_id', 't.slug' ); |
1925 $selects = array( 't.term_id', 't.slug', 'tt.count', 'tt.taxonomy' ); |
1454 break; |
1926 break; |
1455 } |
1927 } |
1456 |
1928 |
1457 $_fields = $fields; |
1929 $_fields = $args['fields']; |
1458 |
1930 |
|
1931 /** |
|
1932 * Filter the fields to select in the terms query. |
|
1933 * |
|
1934 * Field lists modified using this filter will only modify the term fields returned |
|
1935 * by the function when the `$fields` parameter set to 'count' or 'all'. In all other |
|
1936 * cases, the term fields in the results array will be determined by the `$fields` |
|
1937 * parameter alone. |
|
1938 * |
|
1939 * Use of this filter can result in unpredictable behavior, and is not recommended. |
|
1940 * |
|
1941 * @since 2.8.0 |
|
1942 * |
|
1943 * @param array $selects An array of fields to select for the terms query. |
|
1944 * @param array $args An array of term query arguments. |
|
1945 * @param array $taxonomies An array of taxonomies. |
|
1946 */ |
1459 $fields = implode( ', ', apply_filters( 'get_terms_fields', $selects, $args, $taxonomies ) ); |
1947 $fields = implode( ', ', apply_filters( 'get_terms_fields', $selects, $args, $taxonomies ) ); |
1460 |
1948 |
1461 $join = "INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id"; |
1949 $join = "INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id"; |
1462 |
1950 |
1463 $pieces = array( 'fields', 'join', 'where', 'orderby', 'order', 'limits' ); |
1951 $pieces = array( 'fields', 'join', 'where', 'orderby', 'order', 'limits' ); |
|
1952 |
|
1953 /** |
|
1954 * Filter the terms query SQL clauses. |
|
1955 * |
|
1956 * @since 3.1.0 |
|
1957 * |
|
1958 * @param array $pieces Terms query SQL clauses. |
|
1959 * @param array $taxonomies An array of taxonomies. |
|
1960 * @param array $args An array of terms query arguments. |
|
1961 */ |
1464 $clauses = apply_filters( 'terms_clauses', compact( $pieces ), $taxonomies, $args ); |
1962 $clauses = apply_filters( 'terms_clauses', compact( $pieces ), $taxonomies, $args ); |
1465 foreach ( $pieces as $piece ) |
1963 $fields = isset( $clauses[ 'fields' ] ) ? $clauses[ 'fields' ] : ''; |
1466 $$piece = isset( $clauses[ $piece ] ) ? $clauses[ $piece ] : ''; |
1964 $join = isset( $clauses[ 'join' ] ) ? $clauses[ 'join' ] : ''; |
|
1965 $where = isset( $clauses[ 'where' ] ) ? $clauses[ 'where' ] : ''; |
|
1966 $orderby = isset( $clauses[ 'orderby' ] ) ? $clauses[ 'orderby' ] : ''; |
|
1967 $order = isset( $clauses[ 'order' ] ) ? $clauses[ 'order' ] : ''; |
|
1968 $limits = isset( $clauses[ 'limits' ] ) ? $clauses[ 'limits' ] : ''; |
1467 |
1969 |
1468 $query = "SELECT $fields FROM $wpdb->terms AS t $join WHERE $where $orderby $order $limits"; |
1970 $query = "SELECT $fields FROM $wpdb->terms AS t $join WHERE $where $orderby $order $limits"; |
1469 |
1971 |
1470 $fields = $_fields; |
1972 if ( 'count' == $_fields ) { |
1471 |
|
1472 if ( 'count' == $fields ) { |
|
1473 $term_count = $wpdb->get_var($query); |
1973 $term_count = $wpdb->get_var($query); |
1474 return $term_count; |
1974 return $term_count; |
1475 } |
1975 } |
1476 |
1976 |
1477 $terms = $wpdb->get_results($query); |
1977 $terms = $wpdb->get_results($query); |
1478 if ( 'all' == $fields ) { |
1978 if ( 'all' == $_fields ) { |
1479 update_term_cache($terms); |
1979 update_term_cache( $terms ); |
1480 } |
1980 } |
1481 |
1981 |
1482 if ( empty($terms) ) { |
1982 if ( empty($terms) ) { |
1483 wp_cache_add( $cache_key, array(), 'terms', DAY_IN_SECONDS ); |
1983 wp_cache_add( $cache_key, array(), 'terms', DAY_IN_SECONDS ); |
1484 $terms = apply_filters('get_terms', array(), $taxonomies, $args); |
1984 |
|
1985 /** This filter is documented in wp-includes/taxonomy.php */ |
|
1986 $terms = apply_filters( 'get_terms', array(), $taxonomies, $args ); |
1485 return $terms; |
1987 return $terms; |
1486 } |
1988 } |
1487 |
1989 |
1488 if ( $child_of ) { |
1990 if ( $child_of ) { |
1489 $children = _get_term_hierarchy( reset( $taxonomies ) ); |
1991 foreach ( $taxonomies as $_tax ) { |
1490 if ( ! empty( $children ) ) |
1992 $children = _get_term_hierarchy( $_tax ); |
1491 $terms = _get_term_children( $child_of, $terms, reset( $taxonomies ) ); |
1993 if ( ! empty( $children ) ) { |
|
1994 $terms = _get_term_children( $child_of, $terms, $_tax ); |
|
1995 } |
|
1996 } |
1492 } |
1997 } |
1493 |
1998 |
1494 // Update term counts to include children. |
1999 // Update term counts to include children. |
1495 if ( $pad_counts && 'all' == $fields ) |
2000 if ( $args['pad_counts'] && 'all' == $_fields ) { |
1496 _pad_term_counts( $terms, reset( $taxonomies ) ); |
2001 foreach ( $taxonomies as $_tax ) { |
|
2002 _pad_term_counts( $terms, $_tax ); |
|
2003 } |
|
2004 } |
1497 |
2005 |
1498 // Make sure we show empty categories that have children. |
2006 // Make sure we show empty categories that have children. |
1499 if ( $hierarchical && $hide_empty && is_array( $terms ) ) { |
2007 if ( $hierarchical && $args['hide_empty'] && is_array( $terms ) ) { |
1500 foreach ( $terms as $k => $term ) { |
2008 foreach ( $terms as $k => $term ) { |
1501 if ( ! $term->count ) { |
2009 if ( ! $term->count ) { |
1502 $children = _get_term_children( $term->term_id, $terms, reset( $taxonomies ) ); |
2010 $children = get_term_children( $term->term_id, $term->taxonomy ); |
1503 if ( is_array( $children ) ) |
2011 if ( is_array( $children ) ) { |
1504 foreach ( $children as $child ) |
2012 foreach ( $children as $child_id ) { |
1505 if ( $child->count ) |
2013 $child = get_term( $child_id, $term->taxonomy ); |
|
2014 if ( $child->count ) { |
1506 continue 2; |
2015 continue 2; |
|
2016 } |
|
2017 } |
|
2018 } |
1507 |
2019 |
1508 // It really is empty |
2020 // It really is empty |
1509 unset($terms[$k]); |
2021 unset($terms[$k]); |
1510 } |
2022 } |
1511 } |
2023 } |
1512 } |
2024 } |
1513 reset( $terms ); |
|
1514 |
2025 |
1515 $_terms = array(); |
2026 $_terms = array(); |
1516 if ( 'id=>parent' == $fields ) { |
2027 if ( 'id=>parent' == $_fields ) { |
1517 while ( $term = array_shift( $terms ) ) |
2028 foreach ( $terms as $term ) { |
1518 $_terms[$term->term_id] = $term->parent; |
2029 $_terms[ $term->term_id ] = $term->parent; |
1519 } elseif ( 'ids' == $fields ) { |
2030 } |
1520 while ( $term = array_shift( $terms ) ) |
2031 } elseif ( 'ids' == $_fields ) { |
|
2032 foreach ( $terms as $term ) { |
1521 $_terms[] = $term->term_id; |
2033 $_terms[] = $term->term_id; |
1522 } elseif ( 'names' == $fields ) { |
2034 } |
1523 while ( $term = array_shift( $terms ) ) |
2035 } elseif ( 'names' == $_fields ) { |
|
2036 foreach ( $terms as $term ) { |
1524 $_terms[] = $term->name; |
2037 $_terms[] = $term->name; |
1525 } elseif ( 'id=>name' == $fields ) { |
2038 } |
1526 while ( $term = array_shift( $terms ) ) |
2039 } elseif ( 'id=>name' == $_fields ) { |
1527 $_terms[$term->term_id] = $term->name; |
2040 foreach ( $terms as $term ) { |
1528 } elseif ( 'id=>slug' == $fields ) { |
2041 $_terms[ $term->term_id ] = $term->name; |
1529 while ( $term = array_shift( $terms ) ) |
2042 } |
1530 $_terms[$term->term_id] = $term->slug; |
2043 } elseif ( 'id=>slug' == $_fields ) { |
1531 } |
2044 foreach ( $terms as $term ) { |
1532 |
2045 $_terms[ $term->term_id ] = $term->slug; |
1533 if ( ! empty( $_terms ) ) |
2046 } |
|
2047 } |
|
2048 |
|
2049 if ( ! empty( $_terms ) ) { |
1534 $terms = $_terms; |
2050 $terms = $_terms; |
1535 |
2051 } |
1536 if ( $number && is_array( $terms ) && count( $terms ) > $number ) |
2052 |
|
2053 if ( $number && is_array( $terms ) && count( $terms ) > $number ) { |
1537 $terms = array_slice( $terms, $offset, $number ); |
2054 $terms = array_slice( $terms, $offset, $number ); |
|
2055 } |
1538 |
2056 |
1539 wp_cache_add( $cache_key, $terms, 'terms', DAY_IN_SECONDS ); |
2057 wp_cache_add( $cache_key, $terms, 'terms', DAY_IN_SECONDS ); |
1540 |
2058 |
|
2059 /** This filter is documented in wp-includes/taxonomy */ |
1541 $terms = apply_filters( 'get_terms', $terms, $taxonomies, $args ); |
2060 $terms = apply_filters( 'get_terms', $terms, $taxonomies, $args ); |
1542 return $terms; |
2061 return $terms; |
1543 } |
2062 } |
1544 |
2063 |
1545 /** |
2064 /** |
1546 * Check if Term exists. |
2065 * Check if Term exists. |
1547 * |
2066 * |
1548 * Formerly is_term(), introduced in 2.3.0. |
2067 * Formerly is_term(), introduced in 2.3.0. |
1549 * |
2068 * |
1550 * @package WordPress |
|
1551 * @subpackage Taxonomy |
|
1552 * @since 3.0.0 |
2069 * @since 3.0.0 |
1553 * |
2070 * |
1554 * @uses $wpdb |
2071 * @global wpdb $wpdb WordPress database abstraction object. |
1555 * |
2072 * |
1556 * @param int|string $term The term to check |
2073 * @param int|string $term The term to check |
1557 * @param string $taxonomy The taxonomy name to use |
2074 * @param string $taxonomy The taxonomy name to use |
1558 * @param int $parent ID of parent term under which to confine the exists search. |
2075 * @param int $parent Optional. ID of parent term under which to confine the exists search. |
1559 * @return mixed Returns 0 if the term does not exist. Returns the term ID if no taxonomy is specified |
2076 * @return mixed Returns null if the term does not exist. Returns the term ID |
1560 * and the term ID exists. Returns an array of the term ID and the taxonomy if the pairing exists. |
2077 * if no taxonomy is specified and the term ID exists. Returns |
1561 */ |
2078 * an array of the term ID and the term taxonomy ID the taxonomy |
1562 function term_exists($term, $taxonomy = '', $parent = 0) { |
2079 * is specified and the pairing exists. |
|
2080 */ |
|
2081 function term_exists( $term, $taxonomy = '', $parent = null ) { |
1563 global $wpdb; |
2082 global $wpdb; |
1564 |
2083 |
1565 $select = "SELECT term_id FROM $wpdb->terms as t WHERE "; |
2084 $select = "SELECT term_id FROM $wpdb->terms as t WHERE "; |
1566 $tax_select = "SELECT tt.term_id, tt.term_taxonomy_id FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_id = t.term_id WHERE "; |
2085 $tax_select = "SELECT tt.term_id, tt.term_taxonomy_id FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_id = t.term_id WHERE "; |
1567 |
2086 |
1696 * |
2206 * |
1697 * There are enough filters for each context to support a custom filtering |
2207 * There are enough filters for each context to support a custom filtering |
1698 * without creating your own filter function. Simply create a function that |
2208 * without creating your own filter function. Simply create a function that |
1699 * hooks into the filter you need. |
2209 * hooks into the filter you need. |
1700 * |
2210 * |
1701 * @package WordPress |
|
1702 * @subpackage Taxonomy |
|
1703 * @since 2.3.0 |
2211 * @since 2.3.0 |
1704 * |
2212 * |
1705 * @uses $wpdb |
2213 * @global wpdb $wpdb WordPress database abstraction object. |
1706 * |
2214 * |
1707 * @param string $field Term field to sanitize |
2215 * @param string $field Term field to sanitize |
1708 * @param string $value Search for this term value |
2216 * @param string $value Search for this term value |
1709 * @param int $term_id Term ID |
2217 * @param int $term_id Term ID |
1710 * @param string $taxonomy Taxonomy Name |
2218 * @param string $taxonomy Taxonomy Name |
1711 * @param string $context Either edit, db, display, attribute, or js. |
2219 * @param string $context Either edit, db, display, attribute, or js. |
1712 * @return mixed sanitized field |
2220 * @return mixed sanitized field |
1713 */ |
2221 */ |
1714 function sanitize_term_field($field, $value, $term_id, $taxonomy, $context) { |
2222 function sanitize_term_field($field, $value, $term_id, $taxonomy, $context) { |
1715 if ( 'parent' == $field || 'term_id' == $field || 'count' == $field || 'term_group' == $field ) { |
2223 $int_fields = array( 'parent', 'term_id', 'count', 'term_group', 'term_taxonomy_id', 'object_id' ); |
|
2224 if ( in_array( $field, $int_fields ) ) { |
1716 $value = (int) $value; |
2225 $value = (int) $value; |
1717 if ( $value < 0 ) |
2226 if ( $value < 0 ) |
1718 $value = 0; |
2227 $value = 0; |
1719 } |
2228 } |
1720 |
2229 |
1721 if ( 'raw' == $context ) |
2230 if ( 'raw' == $context ) |
1722 return $value; |
2231 return $value; |
1723 |
2232 |
1724 if ( 'edit' == $context ) { |
2233 if ( 'edit' == $context ) { |
1725 $value = apply_filters("edit_term_{$field}", $value, $term_id, $taxonomy); |
2234 |
1726 $value = apply_filters("edit_{$taxonomy}_{$field}", $value, $term_id); |
2235 /** |
|
2236 * Filter a term field to edit before it is sanitized. |
|
2237 * |
|
2238 * The dynamic portion of the filter name, `$field`, refers to the term field. |
|
2239 * |
|
2240 * @since 2.3.0 |
|
2241 * |
|
2242 * @param mixed $value Value of the term field. |
|
2243 * @param int $term_id Term ID. |
|
2244 * @param string $taxonomy Taxonomy slug. |
|
2245 */ |
|
2246 $value = apply_filters( "edit_term_{$field}", $value, $term_id, $taxonomy ); |
|
2247 |
|
2248 /** |
|
2249 * Filter the taxonomy field to edit before it is sanitized. |
|
2250 * |
|
2251 * The dynamic portions of the filter name, `$taxonomy` and `$field`, refer |
|
2252 * to the taxonomy slug and taxonomy field, respectively. |
|
2253 * |
|
2254 * @since 2.3.0 |
|
2255 * |
|
2256 * @param mixed $value Value of the taxonomy field to edit. |
|
2257 * @param int $term_id Term ID. |
|
2258 */ |
|
2259 $value = apply_filters( "edit_{$taxonomy}_{$field}", $value, $term_id ); |
1727 if ( 'description' == $field ) |
2260 if ( 'description' == $field ) |
1728 $value = esc_html($value); // textarea_escaped |
2261 $value = esc_html($value); // textarea_escaped |
1729 else |
2262 else |
1730 $value = esc_attr($value); |
2263 $value = esc_attr($value); |
1731 } else if ( 'db' == $context ) { |
2264 } elseif ( 'db' == $context ) { |
1732 $value = apply_filters("pre_term_{$field}", $value, $taxonomy); |
2265 |
1733 $value = apply_filters("pre_{$taxonomy}_{$field}", $value); |
2266 /** |
|
2267 * Filter a term field value before it is sanitized. |
|
2268 * |
|
2269 * The dynamic portion of the filter name, `$field`, refers to the term field. |
|
2270 * |
|
2271 * @since 2.3.0 |
|
2272 * |
|
2273 * @param mixed $value Value of the term field. |
|
2274 * @param string $taxonomy Taxonomy slug. |
|
2275 */ |
|
2276 $value = apply_filters( "pre_term_{$field}", $value, $taxonomy ); |
|
2277 |
|
2278 /** |
|
2279 * Filter a taxonomy field before it is sanitized. |
|
2280 * |
|
2281 * The dynamic portions of the filter name, `$taxonomy` and `$field`, refer |
|
2282 * to the taxonomy slug and field name, respectively. |
|
2283 * |
|
2284 * @since 2.3.0 |
|
2285 * |
|
2286 * @param mixed $value Value of the taxonomy field. |
|
2287 */ |
|
2288 $value = apply_filters( "pre_{$taxonomy}_{$field}", $value ); |
1734 // Back compat filters |
2289 // Back compat filters |
1735 if ( 'slug' == $field ) |
2290 if ( 'slug' == $field ) { |
1736 $value = apply_filters('pre_category_nicename', $value); |
2291 /** |
1737 |
2292 * Filter the category nicename before it is sanitized. |
1738 } else if ( 'rss' == $context ) { |
2293 * |
1739 $value = apply_filters("term_{$field}_rss", $value, $taxonomy); |
2294 * Use the pre_{$taxonomy}_{$field} hook instead. |
1740 $value = apply_filters("{$taxonomy}_{$field}_rss", $value); |
2295 * |
|
2296 * @since 2.0.3 |
|
2297 * |
|
2298 * @param string $value The category nicename. |
|
2299 */ |
|
2300 $value = apply_filters( 'pre_category_nicename', $value ); |
|
2301 } |
|
2302 |
|
2303 } elseif ( 'rss' == $context ) { |
|
2304 |
|
2305 /** |
|
2306 * Filter the term field for use in RSS. |
|
2307 * |
|
2308 * The dynamic portion of the filter name, `$field`, refers to the term field. |
|
2309 * |
|
2310 * @since 2.3.0 |
|
2311 * |
|
2312 * @param mixed $value Value of the term field. |
|
2313 * @param string $taxonomy Taxonomy slug. |
|
2314 */ |
|
2315 $value = apply_filters( "term_{$field}_rss", $value, $taxonomy ); |
|
2316 |
|
2317 /** |
|
2318 * Filter the taxonomy field for use in RSS. |
|
2319 * |
|
2320 * The dynamic portions of the hook name, `$taxonomy`, and $field, refer |
|
2321 * to the taxonomy slug and field name, respectively. |
|
2322 * |
|
2323 * @since 2.3.0 |
|
2324 * |
|
2325 * @param mixed $value Value of the taxonomy field. |
|
2326 */ |
|
2327 $value = apply_filters( "{$taxonomy}_{$field}_rss", $value ); |
1741 } else { |
2328 } else { |
1742 // Use display filters by default. |
2329 // Use display filters by default. |
1743 $value = apply_filters("term_{$field}", $value, $term_id, $taxonomy, $context); |
2330 |
1744 $value = apply_filters("{$taxonomy}_{$field}", $value, $term_id, $context); |
2331 /** |
1745 } |
2332 * Filter the term field sanitized for display. |
1746 |
2333 * |
1747 if ( 'attribute' == $context ) |
2334 * The dynamic portion of the filter name, `$field`, refers to the term field name. |
|
2335 * |
|
2336 * @since 2.3.0 |
|
2337 * |
|
2338 * @param mixed $value Value of the term field. |
|
2339 * @param int $term_id Term ID. |
|
2340 * @param string $taxonomy Taxonomy slug. |
|
2341 * @param string $context Context to retrieve the term field value. |
|
2342 */ |
|
2343 $value = apply_filters( "term_{$field}", $value, $term_id, $taxonomy, $context ); |
|
2344 |
|
2345 /** |
|
2346 * Filter the taxonomy field sanitized for display. |
|
2347 * |
|
2348 * The dynamic portions of the filter name, `$taxonomy`, and $field, refer |
|
2349 * to the taxonomy slug and taxonomy field, respectively. |
|
2350 * |
|
2351 * @since 2.3.0 |
|
2352 * |
|
2353 * @param mixed $value Value of the taxonomy field. |
|
2354 * @param int $term_id Term ID. |
|
2355 * @param string $context Context to retrieve the taxonomy field value. |
|
2356 */ |
|
2357 $value = apply_filters( "{$taxonomy}_{$field}", $value, $term_id, $context ); |
|
2358 } |
|
2359 |
|
2360 if ( 'attribute' == $context ) { |
1748 $value = esc_attr($value); |
2361 $value = esc_attr($value); |
1749 else if ( 'js' == $context ) |
2362 } elseif ( 'js' == $context ) { |
1750 $value = esc_js($value); |
2363 $value = esc_js($value); |
1751 |
2364 } |
1752 return $value; |
2365 return $value; |
1753 } |
2366 } |
1754 |
2367 |
1755 /** |
2368 /** |
1756 * Count how many terms are in Taxonomy. |
2369 * Count how many terms are in Taxonomy. |
1757 * |
2370 * |
1758 * Default $args is 'hide_empty' which can be 'hide_empty=true' or array('hide_empty' => true). |
2371 * Default $args is 'hide_empty' which can be 'hide_empty=true' or array('hide_empty' => true). |
1759 * |
2372 * |
1760 * @package WordPress |
|
1761 * @subpackage Taxonomy |
|
1762 * @since 2.3.0 |
2373 * @since 2.3.0 |
1763 * |
|
1764 * @uses get_terms() |
|
1765 * @uses wp_parse_args() Turns strings into arrays and merges defaults into an array. |
|
1766 * |
2374 * |
1767 * @param string $taxonomy Taxonomy name |
2375 * @param string $taxonomy Taxonomy name |
1768 * @param array|string $args Overwrite defaults. See get_terms() |
2376 * @param array|string $args Overwrite defaults. See get_terms() |
1769 * @return int|WP_Error How many terms are in $taxonomy. WP_Error if $taxonomy does not exist. |
2377 * @return int|WP_Error How many terms are in $taxonomy. WP_Error if $taxonomy does not exist. |
1770 */ |
2378 */ |
1932 } |
2607 } |
1933 |
2608 |
1934 /** |
2609 /** |
1935 * Retrieves the terms associated with the given object(s), in the supplied taxonomies. |
2610 * Retrieves the terms associated with the given object(s), in the supplied taxonomies. |
1936 * |
2611 * |
1937 * The following information has to do the $args parameter and for what can be |
|
1938 * contained in the string or array of that parameter, if it exists. |
|
1939 * |
|
1940 * The first argument is called, 'orderby' and has the default value of 'name'. |
|
1941 * The other value that is supported is 'count'. |
|
1942 * |
|
1943 * The second argument is called, 'order' and has the default value of 'ASC'. |
|
1944 * The only other value that will be acceptable is 'DESC'. |
|
1945 * |
|
1946 * The final argument supported is called, 'fields' and has the default value of |
|
1947 * 'all'. There are multiple other options that can be used instead. Supported |
|
1948 * values are as follows: 'all', 'ids', 'names', and finally |
|
1949 * 'all_with_object_id'. |
|
1950 * |
|
1951 * The fields argument also decides what will be returned. If 'all' or |
|
1952 * 'all_with_object_id' is chosen or the default kept intact, then all matching |
|
1953 * terms objects will be returned. If either 'ids' or 'names' is used, then an |
|
1954 * array of all matching term ids or term names will be returned respectively. |
|
1955 * |
|
1956 * @package WordPress |
|
1957 * @subpackage Taxonomy |
|
1958 * @since 2.3.0 |
2612 * @since 2.3.0 |
1959 * @uses $wpdb |
2613 * @since 4.2.0 Added support for 'taxonomy', 'parent', and 'term_taxonomy_id' values of `$orderby`. |
1960 * |
2614 * Introduced `$parent` argument. |
1961 * @param int|array $object_ids The ID(s) of the object(s) to retrieve. |
2615 * |
|
2616 * @global wpdb $wpdb WordPress database abstraction object. |
|
2617 * |
|
2618 * @param int|array $object_ids The ID(s) of the object(s) to retrieve. |
1962 * @param string|array $taxonomies The taxonomies to retrieve terms from. |
2619 * @param string|array $taxonomies The taxonomies to retrieve terms from. |
1963 * @param array|string $args Change what is returned |
2620 * @param array|string $args { |
1964 * @return array|WP_Error The requested term data or empty array if no terms found. WP_Error if any of the $taxonomies don't exist. |
2621 * Array of arguments. |
|
2622 * @type string $orderby Field by which results should be sorted. Accepts 'name', 'count', 'slug', 'term_group', |
|
2623 * 'term_order', 'taxonomy', 'parent', or 'term_taxonomy_id'. Default 'name'. |
|
2624 * @type string $order Sort order. Accepts 'ASC' or 'DESC'. Default 'ASC'. |
|
2625 * @type string $fields Fields to return for matched terms. Accepts 'all', 'ids', 'names', and |
|
2626 * 'all_with_object_id'. Note that 'all' or 'all_with_object_id' will result in an array of |
|
2627 * term objects being returned, 'ids' will return an array of integers, and 'names' an array |
|
2628 * of strings. |
|
2629 * @type int $parent Optional. Limit results to the direct children of a given term ID. |
|
2630 * } |
|
2631 * @return array|WP_Error The requested term data or empty array if no terms found. |
|
2632 * WP_Error if any of the $taxonomies don't exist. |
1965 */ |
2633 */ |
1966 function wp_get_object_terms($object_ids, $taxonomies, $args = array()) { |
2634 function wp_get_object_terms($object_ids, $taxonomies, $args = array()) { |
1967 global $wpdb; |
2635 global $wpdb; |
1968 |
2636 |
1969 if ( empty( $object_ids ) || empty( $taxonomies ) ) |
2637 if ( empty( $object_ids ) || empty( $taxonomies ) ) |
1970 return array(); |
2638 return array(); |
1971 |
2639 |
1972 if ( !is_array($taxonomies) ) |
2640 if ( !is_array($taxonomies) ) |
1973 $taxonomies = array($taxonomies); |
2641 $taxonomies = array($taxonomies); |
1974 |
2642 |
1975 foreach ( (array) $taxonomies as $taxonomy ) { |
2643 foreach ( $taxonomies as $taxonomy ) { |
1976 if ( ! taxonomy_exists($taxonomy) ) |
2644 if ( ! taxonomy_exists($taxonomy) ) |
1977 return new WP_Error('invalid_taxonomy', __('Invalid taxonomy')); |
2645 return new WP_Error('invalid_taxonomy', __('Invalid taxonomy')); |
1978 } |
2646 } |
1979 |
2647 |
1980 if ( !is_array($object_ids) ) |
2648 if ( !is_array($object_ids) ) |
1981 $object_ids = array($object_ids); |
2649 $object_ids = array($object_ids); |
1982 $object_ids = array_map('intval', $object_ids); |
2650 $object_ids = array_map('intval', $object_ids); |
1983 |
2651 |
1984 $defaults = array('orderby' => 'name', 'order' => 'ASC', 'fields' => 'all'); |
2652 $defaults = array( |
|
2653 'orderby' => 'name', |
|
2654 'order' => 'ASC', |
|
2655 'fields' => 'all', |
|
2656 'parent' => '', |
|
2657 ); |
1985 $args = wp_parse_args( $args, $defaults ); |
2658 $args = wp_parse_args( $args, $defaults ); |
1986 |
2659 |
1987 $terms = array(); |
2660 $terms = array(); |
1988 if ( count($taxonomies) > 1 ) { |
2661 if ( count($taxonomies) > 1 ) { |
1989 foreach ( $taxonomies as $index => $taxonomy ) { |
2662 foreach ( $taxonomies as $index => $taxonomy ) { |
2027 |
2698 |
2028 $order = strtoupper( $order ); |
2699 $order = strtoupper( $order ); |
2029 if ( '' !== $order && ! in_array( $order, array( 'ASC', 'DESC' ) ) ) |
2700 if ( '' !== $order && ! in_array( $order, array( 'ASC', 'DESC' ) ) ) |
2030 $order = 'ASC'; |
2701 $order = 'ASC'; |
2031 |
2702 |
|
2703 $taxonomy_array = $taxonomies; |
|
2704 $object_id_array = $object_ids; |
2032 $taxonomies = "'" . implode("', '", $taxonomies) . "'"; |
2705 $taxonomies = "'" . implode("', '", $taxonomies) . "'"; |
2033 $object_ids = implode(', ', $object_ids); |
2706 $object_ids = implode(', ', $object_ids); |
2034 |
2707 |
2035 $select_this = ''; |
2708 $select_this = ''; |
2036 if ( 'all' == $fields ) |
2709 if ( 'all' == $fields ) { |
2037 $select_this = 't.*, tt.*'; |
2710 $select_this = 't.*, tt.*'; |
2038 else if ( 'ids' == $fields ) |
2711 } elseif ( 'ids' == $fields ) { |
2039 $select_this = 't.term_id'; |
2712 $select_this = 't.term_id'; |
2040 else if ( 'names' == $fields ) |
2713 } elseif ( 'names' == $fields ) { |
2041 $select_this = 't.name'; |
2714 $select_this = 't.name'; |
2042 else if ( 'slugs' == $fields ) |
2715 } elseif ( 'slugs' == $fields ) { |
2043 $select_this = 't.slug'; |
2716 $select_this = 't.slug'; |
2044 else if ( 'all_with_object_id' == $fields ) |
2717 } elseif ( 'all_with_object_id' == $fields ) { |
2045 $select_this = 't.*, tt.*, tr.object_id'; |
2718 $select_this = 't.*, tt.*, tr.object_id'; |
2046 |
2719 } |
2047 $query = "SELECT $select_this FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_id = t.term_id INNER JOIN $wpdb->term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND tr.object_id IN ($object_ids) $orderby $order"; |
2720 |
2048 |
2721 $where = array( |
|
2722 "tt.taxonomy IN ($taxonomies)", |
|
2723 "tr.object_id IN ($object_ids)", |
|
2724 ); |
|
2725 |
|
2726 if ( '' !== $args['parent'] ) { |
|
2727 $where[] = $wpdb->prepare( 'tt.parent = %d', $args['parent'] ); |
|
2728 } |
|
2729 |
|
2730 $where = implode( ' AND ', $where ); |
|
2731 |
|
2732 $query = "SELECT $select_this FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_id = t.term_id INNER JOIN $wpdb->term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE $where $orderby $order"; |
|
2733 |
|
2734 $objects = false; |
2049 if ( 'all' == $fields || 'all_with_object_id' == $fields ) { |
2735 if ( 'all' == $fields || 'all_with_object_id' == $fields ) { |
2050 $terms = array_merge($terms, $wpdb->get_results($query)); |
2736 $_terms = $wpdb->get_results( $query ); |
2051 update_term_cache($terms); |
2737 foreach ( $_terms as $key => $term ) { |
2052 } else if ( 'ids' == $fields || 'names' == $fields || 'slugs' == $fields ) { |
2738 $_terms[$key] = sanitize_term( $term, $taxonomy, 'raw' ); |
2053 $terms = array_merge($terms, $wpdb->get_col($query)); |
2739 } |
2054 } else if ( 'tt_ids' == $fields ) { |
2740 $terms = array_merge( $terms, $_terms ); |
|
2741 update_term_cache( $terms ); |
|
2742 $objects = true; |
|
2743 } elseif ( 'ids' == $fields || 'names' == $fields || 'slugs' == $fields ) { |
|
2744 $_terms = $wpdb->get_col( $query ); |
|
2745 $_field = ( 'ids' == $fields ) ? 'term_id' : 'name'; |
|
2746 foreach ( $_terms as $key => $term ) { |
|
2747 $_terms[$key] = sanitize_term_field( $_field, $term, $term, $taxonomy, 'raw' ); |
|
2748 } |
|
2749 $terms = array_merge( $terms, $_terms ); |
|
2750 } elseif ( 'tt_ids' == $fields ) { |
2055 $terms = $wpdb->get_col("SELECT tr.term_taxonomy_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tr.object_id IN ($object_ids) AND tt.taxonomy IN ($taxonomies) $orderby $order"); |
2751 $terms = $wpdb->get_col("SELECT tr.term_taxonomy_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tr.object_id IN ($object_ids) AND tt.taxonomy IN ($taxonomies) $orderby $order"); |
2056 } |
2752 foreach ( $terms as $key => $tt_id ) { |
2057 |
2753 $terms[$key] = sanitize_term_field( 'term_taxonomy_id', $tt_id, 0, $taxonomy, 'raw' ); // 0 should be the term id, however is not needed when using raw context. |
2058 if ( ! $terms ) |
2754 } |
|
2755 } |
|
2756 |
|
2757 if ( ! $terms ) { |
2059 $terms = array(); |
2758 $terms = array(); |
2060 |
2759 } elseif ( $objects && 'all_with_object_id' !== $fields ) { |
2061 return apply_filters('wp_get_object_terms', $terms, $object_ids, $taxonomies, $args); |
2760 $_tt_ids = array(); |
|
2761 $_terms = array(); |
|
2762 foreach ( $terms as $term ) { |
|
2763 if ( in_array( $term->term_taxonomy_id, $_tt_ids ) ) { |
|
2764 continue; |
|
2765 } |
|
2766 |
|
2767 $_tt_ids[] = $term->term_taxonomy_id; |
|
2768 $_terms[] = $term; |
|
2769 } |
|
2770 $terms = $_terms; |
|
2771 } elseif ( ! $objects ) { |
|
2772 $terms = array_values( array_unique( $terms ) ); |
|
2773 } |
|
2774 |
|
2775 /** |
|
2776 * Filter the terms for a given object or objects. |
|
2777 * |
|
2778 * @since 4.2.0 |
|
2779 * |
|
2780 * @param array $terms An array of terms for the given object or objects. |
|
2781 * @param array $object_id_array Array of object IDs for which `$terms` were retrieved. |
|
2782 * @param array $taxonomy_array Array of taxonomies from which `$terms` were retrieved. |
|
2783 * @param array $args An array of arguments for retrieving terms for the given |
|
2784 * object(s). See wp_get_object_terms() for details. |
|
2785 */ |
|
2786 $terms = apply_filters( 'get_object_terms', $terms, $object_id_array, $taxonomy_array, $args ); |
|
2787 |
|
2788 /** |
|
2789 * Filter the terms for a given object or objects. |
|
2790 * |
|
2791 * The `$taxonomies` parameter passed to this filter is formatted as a SQL fragment. The |
|
2792 * {@see 'get_object_terms'} filter is recommended as an alternative. |
|
2793 * |
|
2794 * @since 2.8.0 |
|
2795 * |
|
2796 * @param array $terms An array of terms for the given object or objects. |
|
2797 * @param int|array $object_ids Object ID or array of IDs. |
|
2798 * @param string $taxonomies SQL-formatted (comma-separated and quoted) list of taxonomy names. |
|
2799 * @param array $args An array of arguments for retrieving terms for the given object(s). |
|
2800 * See {@see wp_get_object_terms()} for details. |
|
2801 */ |
|
2802 return apply_filters( 'wp_get_object_terms', $terms, $object_ids, $taxonomies, $args ); |
2062 } |
2803 } |
2063 |
2804 |
2064 /** |
2805 /** |
2065 * Add a new term to the database. |
2806 * Add a new term to the database. |
2066 * |
2807 * |
2084 * a WP_Error object will be returned. |
2825 * a WP_Error object will be returned. |
2085 * |
2826 * |
2086 * If the term already exists on the same hierarchical level, |
2827 * If the term already exists on the same hierarchical level, |
2087 * or the term slug and name are not unique, a WP_Error object will be returned. |
2828 * or the term slug and name are not unique, a WP_Error object will be returned. |
2088 * |
2829 * |
2089 * @global wpdb $wpdb The WordPress database object. |
2830 * @global wpdb $wpdb WordPress database abstraction object. |
2090 |
2831 |
2091 * @since 2.3.0 |
2832 * @since 2.3.0 |
2092 * |
2833 * |
2093 * @param string $term The term to add or update. |
2834 * @param string $term The term to add or update. |
2094 * @param string $taxonomy The taxonomy to which to add the term |
2835 * @param string $taxonomy The taxonomy to which to add the term. |
2095 * @param array|string $args { |
2836 * @param array|string $args { |
2096 * Arguments to change values of the inserted term. |
2837 * Optional. Array or string of arguments for inserting a term. |
2097 * |
2838 * |
2098 * @type string 'alias_of' Slug of the term to make this term an alias of. |
2839 * @type string $alias_of Slug of the term to make this term an alias of. |
2099 * Default empty string. Accepts a term slug. |
2840 * Default empty string. Accepts a term slug. |
2100 * @type string 'description' The term description. |
2841 * @type string $description The term description. Default empty string. |
2101 * Default empty string. |
2842 * @type int $parent The id of the parent term. Default 0. |
2102 * @type int 'parent' The id of the parent term. |
2843 * @type string $slug The term slug to use. Default empty string. |
2103 * Default 0. |
|
2104 * @type string 'slug' The term slug to use. |
|
2105 * Default empty string. |
|
2106 * } |
2844 * } |
2107 * @return array|WP_Error An array containing the term_id and term_taxonomy_id, WP_Error otherwise. |
2845 * @return array|WP_Error An array containing the `term_id` and `term_taxonomy_id`, |
|
2846 * {@see WP_Error} otherwise. |
2108 */ |
2847 */ |
2109 function wp_insert_term( $term, $taxonomy, $args = array() ) { |
2848 function wp_insert_term( $term, $taxonomy, $args = array() ) { |
2110 global $wpdb; |
2849 global $wpdb; |
2111 |
2850 |
2112 if ( ! taxonomy_exists($taxonomy) ) |
2851 if ( ! taxonomy_exists($taxonomy) ) { |
2113 return new WP_Error('invalid_taxonomy', __('Invalid taxonomy')); |
2852 return new WP_Error('invalid_taxonomy', __('Invalid taxonomy')); |
2114 |
2853 } |
|
2854 /** |
|
2855 * Filter a term before it is sanitized and inserted into the database. |
|
2856 * |
|
2857 * @since 3.0.0 |
|
2858 * |
|
2859 * @param string $term The term to add or update. |
|
2860 * @param string $taxonomy Taxonomy slug. |
|
2861 */ |
2115 $term = apply_filters( 'pre_insert_term', $term, $taxonomy ); |
2862 $term = apply_filters( 'pre_insert_term', $term, $taxonomy ); |
2116 if ( is_wp_error( $term ) ) |
2863 if ( is_wp_error( $term ) ) { |
2117 return $term; |
2864 return $term; |
2118 |
2865 } |
2119 if ( is_int($term) && 0 == $term ) |
2866 if ( is_int($term) && 0 == $term ) { |
2120 return new WP_Error('invalid_term_id', __('Invalid term ID')); |
2867 return new WP_Error('invalid_term_id', __('Invalid term ID')); |
2121 |
2868 } |
2122 if ( '' == trim($term) ) |
2869 if ( '' == trim($term) ) { |
2123 return new WP_Error('empty_term_name', __('A name is required for this term')); |
2870 return new WP_Error('empty_term_name', __('A name is required for this term')); |
2124 |
2871 } |
2125 $defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => ''); |
2872 $defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => ''); |
2126 $args = wp_parse_args($args, $defaults); |
2873 $args = wp_parse_args( $args, $defaults ); |
|
2874 |
|
2875 if ( $args['parent'] > 0 && ! term_exists( (int) $args['parent'] ) ) { |
|
2876 return new WP_Error( 'missing_parent', __( 'Parent term does not exist.' ) ); |
|
2877 } |
2127 $args['name'] = $term; |
2878 $args['name'] = $term; |
2128 $args['taxonomy'] = $taxonomy; |
2879 $args['taxonomy'] = $taxonomy; |
2129 $args = sanitize_term($args, $taxonomy, 'db'); |
2880 $args = sanitize_term($args, $taxonomy, 'db'); |
2130 extract($args, EXTR_SKIP); |
|
2131 |
2881 |
2132 // expected_slashed ($name) |
2882 // expected_slashed ($name) |
2133 $name = wp_unslash($name); |
2883 $name = wp_unslash( $args['name'] ); |
2134 $description = wp_unslash($description); |
2884 $description = wp_unslash( $args['description'] ); |
2135 |
2885 $parent = (int) $args['parent']; |
2136 if ( empty($slug) ) |
2886 |
2137 $slug = sanitize_title($name); |
2887 $slug_provided = ! empty( $args['slug'] ); |
|
2888 if ( ! $slug_provided ) { |
|
2889 $slug = sanitize_title( $name ); |
|
2890 } else { |
|
2891 $slug = $args['slug']; |
|
2892 } |
2138 |
2893 |
2139 $term_group = 0; |
2894 $term_group = 0; |
2140 if ( $alias_of ) { |
2895 if ( $args['alias_of'] ) { |
2141 $alias = $wpdb->get_row( $wpdb->prepare( "SELECT term_id, term_group FROM $wpdb->terms WHERE slug = %s", $alias_of) ); |
2896 $alias = get_term_by( 'slug', $args['alias_of'], $taxonomy ); |
2142 if ( $alias->term_group ) { |
2897 if ( ! empty( $alias->term_group ) ) { |
2143 // The alias we want is already in a group, so let's use that one. |
2898 // The alias we want is already in a group, so let's use that one. |
2144 $term_group = $alias->term_group; |
2899 $term_group = $alias->term_group; |
2145 } else { |
2900 } elseif ( ! empty( $alias->term_id ) ) { |
2146 // The alias isn't in a group, so let's create a new one and firstly add the alias term to it. |
2901 /* |
|
2902 * The alias is not in a group, so we create a new one |
|
2903 * and add the alias to it. |
|
2904 */ |
2147 $term_group = $wpdb->get_var("SELECT MAX(term_group) FROM $wpdb->terms") + 1; |
2905 $term_group = $wpdb->get_var("SELECT MAX(term_group) FROM $wpdb->terms") + 1; |
2148 do_action( 'edit_terms', $alias->term_id, $taxonomy ); |
2906 |
2149 $wpdb->update($wpdb->terms, compact('term_group'), array('term_id' => $alias->term_id) ); |
2907 wp_update_term( $alias->term_id, $taxonomy, array( |
2150 do_action( 'edited_terms', $alias->term_id, $taxonomy ); |
2908 'term_group' => $term_group, |
2151 } |
2909 ) ); |
2152 } |
2910 } |
2153 |
2911 } |
2154 if ( $term_id = term_exists($slug) ) { |
2912 |
2155 $existing_term = $wpdb->get_row( $wpdb->prepare( "SELECT name FROM $wpdb->terms WHERE term_id = %d", $term_id), ARRAY_A ); |
2913 /* |
2156 // We've got an existing term in the same taxonomy, which matches the name of the new term: |
2914 * Prevent the creation of terms with duplicate names at the same level of a taxonomy hierarchy, |
2157 if ( is_taxonomy_hierarchical($taxonomy) && $existing_term['name'] == $name && $exists = term_exists( (int) $term_id, $taxonomy ) ) { |
2915 * unless a unique slug has been explicitly provided. |
2158 // Hierarchical, and it matches an existing term, Do not allow same "name" in the same level. |
2916 */ |
2159 $siblings = get_terms($taxonomy, array('fields' => 'names', 'get' => 'all', 'parent' => (int)$parent) ); |
2917 if ( $name_match = get_term_by( 'name', $name, $taxonomy ) ) { |
2160 if ( in_array($name, $siblings) ) { |
2918 $slug_match = get_term_by( 'slug', $slug, $taxonomy ); |
2161 return new WP_Error('term_exists', __('A term with the name provided already exists with this parent.'), $exists['term_id']); |
2919 if ( ! $slug_provided || $name_match->slug === $slug || $slug_match ) { |
|
2920 if ( is_taxonomy_hierarchical( $taxonomy ) ) { |
|
2921 $siblings = get_terms( $taxonomy, array( 'get' => 'all', 'parent' => $parent ) ); |
|
2922 |
|
2923 $existing_term = null; |
|
2924 if ( $name_match->slug === $slug && in_array( $name, wp_list_pluck( $siblings, 'name' ) ) ) { |
|
2925 $existing_term = $name_match; |
|
2926 } elseif ( $slug_match && in_array( $slug, wp_list_pluck( $siblings, 'slug' ) ) ) { |
|
2927 $existing_term = $slug_match; |
|
2928 } |
|
2929 |
|
2930 if ( $existing_term ) { |
|
2931 return new WP_Error( 'term_exists', __( 'A term with the name already exists with this parent.' ), $existing_term->term_id ); |
|
2932 } |
2162 } else { |
2933 } else { |
2163 $slug = wp_unique_term_slug($slug, (object) $args); |
2934 return new WP_Error( 'term_exists', __( 'A term with the name already exists in this taxonomy.' ), $name_match->term_id ); |
2164 if ( false === $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ) ) |
|
2165 return new WP_Error('db_insert_error', __('Could not insert term into the database'), $wpdb->last_error); |
|
2166 $term_id = (int) $wpdb->insert_id; |
|
2167 } |
2935 } |
2168 } elseif ( $existing_term['name'] != $name ) { |
2936 } |
2169 // We've got an existing term, with a different name, Create the new term. |
2937 } |
2170 $slug = wp_unique_term_slug($slug, (object) $args); |
2938 |
2171 if ( false === $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ) ) |
2939 $slug = wp_unique_term_slug( $slug, (object) $args ); |
2172 return new WP_Error('db_insert_error', __('Could not insert term into the database'), $wpdb->last_error); |
2940 |
2173 $term_id = (int) $wpdb->insert_id; |
2941 if ( false === $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ) ) { |
2174 } elseif ( $exists = term_exists( (int) $term_id, $taxonomy ) ) { |
2942 return new WP_Error( 'db_insert_error', __( 'Could not insert term into the database' ), $wpdb->last_error ); |
2175 // Same name, same slug. |
2943 } |
2176 return new WP_Error('term_exists', __('A term with the name provided already exists.'), $exists['term_id']); |
2944 |
2177 } |
2945 $term_id = (int) $wpdb->insert_id; |
2178 } else { |
|
2179 // This term does not exist at all in the database, Create it. |
|
2180 $slug = wp_unique_term_slug($slug, (object) $args); |
|
2181 if ( false === $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ) ) |
|
2182 return new WP_Error('db_insert_error', __('Could not insert term into the database'), $wpdb->last_error); |
|
2183 $term_id = (int) $wpdb->insert_id; |
|
2184 } |
|
2185 |
2946 |
2186 // Seems unreachable, However, Is used in the case that a term name is provided, which sanitizes to an empty string. |
2947 // Seems unreachable, However, Is used in the case that a term name is provided, which sanitizes to an empty string. |
2187 if ( empty($slug) ) { |
2948 if ( empty($slug) ) { |
2188 $slug = sanitize_title($slug, $term_id); |
2949 $slug = sanitize_title($slug, $term_id); |
|
2950 |
|
2951 /** This action is documented in wp-includes/taxonomy.php */ |
2189 do_action( 'edit_terms', $term_id, $taxonomy ); |
2952 do_action( 'edit_terms', $term_id, $taxonomy ); |
2190 $wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) ); |
2953 $wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) ); |
|
2954 |
|
2955 /** This action is documented in wp-includes/taxonomy.php */ |
2191 do_action( 'edited_terms', $term_id, $taxonomy ); |
2956 do_action( 'edited_terms', $term_id, $taxonomy ); |
2192 } |
2957 } |
2193 |
2958 |
2194 $tt_id = $wpdb->get_var( $wpdb->prepare( "SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id ) ); |
2959 $tt_id = $wpdb->get_var( $wpdb->prepare( "SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id ) ); |
2195 |
2960 |
2196 if ( !empty($tt_id) ) |
2961 if ( !empty($tt_id) ) { |
2197 return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id); |
2962 return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id); |
2198 |
2963 } |
2199 $wpdb->insert( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent') + array( 'count' => 0 ) ); |
2964 $wpdb->insert( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent') + array( 'count' => 0 ) ); |
2200 $tt_id = (int) $wpdb->insert_id; |
2965 $tt_id = (int) $wpdb->insert_id; |
2201 |
2966 |
2202 do_action("create_term", $term_id, $tt_id, $taxonomy); |
2967 /* |
2203 do_action("create_$taxonomy", $term_id, $tt_id); |
2968 * Sanity check: if we just created a term with the same parent + taxonomy + slug but a higher term_id than |
2204 |
2969 * an existing term, then we have unwittingly created a duplicate term. Delete the dupe, and use the term_id |
2205 $term_id = apply_filters('term_id_filter', $term_id, $tt_id); |
2970 * and term_taxonomy_id of the older term instead. Then return out of the function so that the "create" hooks |
|
2971 * are not fired. |
|
2972 */ |
|
2973 $duplicate_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.term_id, tt.term_taxonomy_id FROM $wpdb->terms t INNER JOIN $wpdb->term_taxonomy tt ON ( tt.term_id = t.term_id ) WHERE t.slug = %s AND tt.parent = %d AND tt.taxonomy = %s AND t.term_id < %d AND tt.term_taxonomy_id != %d", $slug, $parent, $taxonomy, $term_id, $tt_id ) ); |
|
2974 if ( $duplicate_term ) { |
|
2975 $wpdb->delete( $wpdb->terms, array( 'term_id' => $term_id ) ); |
|
2976 $wpdb->delete( $wpdb->term_taxonomy, array( 'term_taxonomy_id' => $tt_id ) ); |
|
2977 |
|
2978 $term_id = (int) $duplicate_term->term_id; |
|
2979 $tt_id = (int) $duplicate_term->term_taxonomy_id; |
|
2980 |
|
2981 clean_term_cache( $term_id, $taxonomy ); |
|
2982 return array( 'term_id' => $term_id, 'term_taxonomy_id' => $tt_id ); |
|
2983 } |
|
2984 |
|
2985 /** |
|
2986 * Fires immediately after a new term is created, before the term cache is cleaned. |
|
2987 * |
|
2988 * @since 2.3.0 |
|
2989 * |
|
2990 * @param int $term_id Term ID. |
|
2991 * @param int $tt_id Term taxonomy ID. |
|
2992 * @param string $taxonomy Taxonomy slug. |
|
2993 */ |
|
2994 do_action( "create_term", $term_id, $tt_id, $taxonomy ); |
|
2995 |
|
2996 /** |
|
2997 * Fires after a new term is created for a specific taxonomy. |
|
2998 * |
|
2999 * The dynamic portion of the hook name, `$taxonomy`, refers |
|
3000 * to the slug of the taxonomy the term was created for. |
|
3001 * |
|
3002 * @since 2.3.0 |
|
3003 * |
|
3004 * @param int $term_id Term ID. |
|
3005 * @param int $tt_id Term taxonomy ID. |
|
3006 */ |
|
3007 do_action( "create_$taxonomy", $term_id, $tt_id ); |
|
3008 |
|
3009 /** |
|
3010 * Filter the term ID after a new term is created. |
|
3011 * |
|
3012 * @since 2.3.0 |
|
3013 * |
|
3014 * @param int $term_id Term ID. |
|
3015 * @param int $tt_id Taxonomy term ID. |
|
3016 */ |
|
3017 $term_id = apply_filters( 'term_id_filter', $term_id, $tt_id ); |
2206 |
3018 |
2207 clean_term_cache($term_id, $taxonomy); |
3019 clean_term_cache($term_id, $taxonomy); |
2208 |
3020 |
2209 do_action("created_term", $term_id, $tt_id, $taxonomy); |
3021 /** |
2210 do_action("created_$taxonomy", $term_id, $tt_id); |
3022 * Fires after a new term is created, and after the term cache has been cleaned. |
|
3023 * |
|
3024 * @since 2.3.0 |
|
3025 */ |
|
3026 do_action( "created_term", $term_id, $tt_id, $taxonomy ); |
|
3027 |
|
3028 /** |
|
3029 * Fires after a new term in a specific taxonomy is created, and after the term |
|
3030 * cache has been cleaned. |
|
3031 * |
|
3032 * @since 2.3.0 |
|
3033 * |
|
3034 * @param int $term_id Term ID. |
|
3035 * @param int $tt_id Term taxonomy ID. |
|
3036 */ |
|
3037 do_action( "created_$taxonomy", $term_id, $tt_id ); |
2211 |
3038 |
2212 return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id); |
3039 return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id); |
2213 } |
3040 } |
2214 |
3041 |
2215 /** |
3042 /** |
2482 * will be created for you. |
3351 * will be created for you. |
2483 * |
3352 * |
2484 * For what can be overrode in $args, check the term scheme can contain and stay |
3353 * For what can be overrode in $args, check the term scheme can contain and stay |
2485 * away from the term keys. |
3354 * away from the term keys. |
2486 * |
3355 * |
2487 * @package WordPress |
|
2488 * @subpackage Taxonomy |
|
2489 * @since 2.3.0 |
3356 * @since 2.3.0 |
2490 * |
3357 * |
2491 * @uses $wpdb |
3358 * @global wpdb $wpdb WordPress database abstraction object. |
2492 * @uses do_action() Will call both 'edit_term' and 'edit_$taxonomy' twice. |
|
2493 * @uses apply_filters() Will call the 'term_id_filter' filter and pass the term |
|
2494 * id and taxonomy id. |
|
2495 * |
3359 * |
2496 * @param int $term_id The ID of the term |
3360 * @param int $term_id The ID of the term |
2497 * @param string $taxonomy The context in which to relate the term to the object. |
3361 * @param string $taxonomy The context in which to relate the term to the object. |
2498 * @param array|string $args Overwrite term field values |
3362 * @param array|string $args Overwrite term field values |
2499 * @return array|WP_Error Returns Term ID and Taxonomy Term ID |
3363 * @return array|WP_Error Returns Term ID and Taxonomy Term ID |
2500 */ |
3364 */ |
2501 function wp_update_term( $term_id, $taxonomy, $args = array() ) { |
3365 function wp_update_term( $term_id, $taxonomy, $args = array() ) { |
2502 global $wpdb; |
3366 global $wpdb; |
2503 |
3367 |
2504 if ( ! taxonomy_exists($taxonomy) ) |
3368 if ( ! taxonomy_exists( $taxonomy ) ) { |
2505 return new WP_Error('invalid_taxonomy', __('Invalid taxonomy')); |
3369 return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) ); |
|
3370 } |
2506 |
3371 |
2507 $term_id = (int) $term_id; |
3372 $term_id = (int) $term_id; |
2508 |
3373 |
2509 // First, get all of the original args |
3374 // First, get all of the original args |
2510 $term = get_term ($term_id, $taxonomy, ARRAY_A); |
3375 $term = get_term( $term_id, $taxonomy, ARRAY_A ); |
2511 |
3376 |
2512 if ( is_wp_error( $term ) ) |
3377 if ( is_wp_error( $term ) ) { |
2513 return $term; |
3378 return $term; |
|
3379 } |
|
3380 |
|
3381 if ( ! $term ) { |
|
3382 return new WP_Error( 'invalid_term', __( 'Empty Term' ) ); |
|
3383 } |
2514 |
3384 |
2515 // Escape data pulled from DB. |
3385 // Escape data pulled from DB. |
2516 $term = wp_slash($term); |
3386 $term = wp_slash($term); |
2517 |
3387 |
2518 // Merge old and new args with new args overwriting old ones. |
3388 // Merge old and new args with new args overwriting old ones. |
2519 $args = array_merge($term, $args); |
3389 $args = array_merge($term, $args); |
2520 |
3390 |
2521 $defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => ''); |
3391 $defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => ''); |
2522 $args = wp_parse_args($args, $defaults); |
3392 $args = wp_parse_args($args, $defaults); |
2523 $args = sanitize_term($args, $taxonomy, 'db'); |
3393 $args = sanitize_term($args, $taxonomy, 'db'); |
2524 extract($args, EXTR_SKIP); |
3394 $parsed_args = $args; |
2525 |
3395 |
2526 // expected_slashed ($name) |
3396 // expected_slashed ($name) |
2527 $name = wp_unslash($name); |
3397 $name = wp_unslash( $args['name'] ); |
2528 $description = wp_unslash($description); |
3398 $description = wp_unslash( $args['description'] ); |
|
3399 |
|
3400 $parsed_args['name'] = $name; |
|
3401 $parsed_args['description'] = $description; |
2529 |
3402 |
2530 if ( '' == trim($name) ) |
3403 if ( '' == trim($name) ) |
2531 return new WP_Error('empty_term_name', __('A name is required for this term')); |
3404 return new WP_Error('empty_term_name', __('A name is required for this term')); |
2532 |
3405 |
|
3406 if ( $parsed_args['parent'] > 0 && ! term_exists( (int) $parsed_args['parent'] ) ) { |
|
3407 return new WP_Error( 'missing_parent', __( 'Parent term does not exist.' ) ); |
|
3408 } |
|
3409 |
2533 $empty_slug = false; |
3410 $empty_slug = false; |
2534 if ( empty($slug) ) { |
3411 if ( empty( $args['slug'] ) ) { |
2535 $empty_slug = true; |
3412 $empty_slug = true; |
2536 $slug = sanitize_title($name); |
3413 $slug = sanitize_title($name); |
2537 } |
3414 } else { |
2538 |
3415 $slug = $args['slug']; |
2539 if ( $alias_of ) { |
3416 } |
2540 $alias = $wpdb->get_row( $wpdb->prepare( "SELECT term_id, term_group FROM $wpdb->terms WHERE slug = %s", $alias_of) ); |
3417 |
2541 if ( $alias->term_group ) { |
3418 $parsed_args['slug'] = $slug; |
|
3419 |
|
3420 $term_group = isset( $parsed_args['term_group'] ) ? $parsed_args['term_group'] : 0; |
|
3421 if ( $args['alias_of'] ) { |
|
3422 $alias = get_term_by( 'slug', $args['alias_of'], $taxonomy ); |
|
3423 if ( ! empty( $alias->term_group ) ) { |
2542 // The alias we want is already in a group, so let's use that one. |
3424 // The alias we want is already in a group, so let's use that one. |
2543 $term_group = $alias->term_group; |
3425 $term_group = $alias->term_group; |
2544 } else { |
3426 } elseif ( ! empty( $alias->term_id ) ) { |
2545 // The alias isn't in a group, so let's create a new one and firstly add the alias term to it. |
3427 /* |
|
3428 * The alias is not in a group, so we create a new one |
|
3429 * and add the alias to it. |
|
3430 */ |
2546 $term_group = $wpdb->get_var("SELECT MAX(term_group) FROM $wpdb->terms") + 1; |
3431 $term_group = $wpdb->get_var("SELECT MAX(term_group) FROM $wpdb->terms") + 1; |
2547 do_action( 'edit_terms', $alias->term_id, $taxonomy ); |
3432 |
2548 $wpdb->update( $wpdb->terms, compact('term_group'), array( 'term_id' => $alias->term_id ) ); |
3433 wp_update_term( $alias->term_id, $taxonomy, array( |
2549 do_action( 'edited_terms', $alias->term_id, $taxonomy ); |
3434 'term_group' => $term_group, |
2550 } |
3435 ) ); |
2551 } |
3436 } |
2552 |
3437 |
2553 // Check $parent to see if it will cause a hierarchy loop |
3438 $parsed_args['term_group'] = $term_group; |
2554 $parent = apply_filters( 'wp_update_term_parent', $parent, $term_id, $taxonomy, compact( array_keys( $args ) ), $args ); |
3439 } |
|
3440 |
|
3441 /** |
|
3442 * Filter the term parent. |
|
3443 * |
|
3444 * Hook to this filter to see if it will cause a hierarchy loop. |
|
3445 * |
|
3446 * @since 3.1.0 |
|
3447 * |
|
3448 * @param int $parent ID of the parent term. |
|
3449 * @param int $term_id Term ID. |
|
3450 * @param string $taxonomy Taxonomy slug. |
|
3451 * @param array $parsed_args An array of potentially altered update arguments for the given term. |
|
3452 * @param array $args An array of update arguments for the given term. |
|
3453 */ |
|
3454 $parent = apply_filters( 'wp_update_term_parent', $args['parent'], $term_id, $taxonomy, $parsed_args, $args ); |
2555 |
3455 |
2556 // Check for duplicate slug |
3456 // Check for duplicate slug |
2557 $id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms WHERE slug = %s", $slug ) ); |
3457 $duplicate = get_term_by( 'slug', $slug, $taxonomy ); |
2558 if ( $id && ($id != $term_id) ) { |
3458 if ( $duplicate && $duplicate->term_id != $term_id ) { |
2559 // If an empty slug was passed or the parent changed, reset the slug to something unique. |
3459 // If an empty slug was passed or the parent changed, reset the slug to something unique. |
2560 // Otherwise, bail. |
3460 // Otherwise, bail. |
2561 if ( $empty_slug || ( $parent != $term['parent']) ) |
3461 if ( $empty_slug || ( $parent != $term['parent']) ) |
2562 $slug = wp_unique_term_slug($slug, (object) $args); |
3462 $slug = wp_unique_term_slug($slug, (object) $args); |
2563 else |
3463 else |
2564 return new WP_Error('duplicate_term_slug', sprintf(__('The slug “%s” is already in use by another term'), $slug)); |
3464 return new WP_Error('duplicate_term_slug', sprintf(__('The slug “%s” is already in use by another term'), $slug)); |
2565 } |
3465 } |
|
3466 |
|
3467 $tt_id = $wpdb->get_var( $wpdb->prepare( "SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id) ); |
|
3468 |
|
3469 // Check whether this is a shared term that needs splitting. |
|
3470 $_term_id = _split_shared_term( $term_id, $tt_id ); |
|
3471 if ( ! is_wp_error( $_term_id ) ) { |
|
3472 $term_id = $_term_id; |
|
3473 } |
|
3474 |
|
3475 /** |
|
3476 * Fires immediately before the given terms are edited. |
|
3477 * |
|
3478 * @since 2.9.0 |
|
3479 * |
|
3480 * @param int $term_id Term ID. |
|
3481 * @param string $taxonomy Taxonomy slug. |
|
3482 */ |
2566 do_action( 'edit_terms', $term_id, $taxonomy ); |
3483 do_action( 'edit_terms', $term_id, $taxonomy ); |
2567 $wpdb->update($wpdb->terms, compact( 'name', 'slug', 'term_group' ), compact( 'term_id' ) ); |
3484 $wpdb->update($wpdb->terms, compact( 'name', 'slug', 'term_group' ), compact( 'term_id' ) ); |
2568 if ( empty($slug) ) { |
3485 if ( empty($slug) ) { |
2569 $slug = sanitize_title($name, $term_id); |
3486 $slug = sanitize_title($name, $term_id); |
2570 $wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) ); |
3487 $wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) ); |
2571 } |
3488 } |
|
3489 |
|
3490 /** |
|
3491 * Fires immediately after the given terms are edited. |
|
3492 * |
|
3493 * @since 2.9.0 |
|
3494 * |
|
3495 * @param int $term_id Term ID |
|
3496 * @param string $taxonomy Taxonomy slug. |
|
3497 */ |
2572 do_action( 'edited_terms', $term_id, $taxonomy ); |
3498 do_action( 'edited_terms', $term_id, $taxonomy ); |
2573 |
3499 |
2574 $tt_id = $wpdb->get_var( $wpdb->prepare( "SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id) ); |
3500 /** |
|
3501 * Fires immediate before a term-taxonomy relationship is updated. |
|
3502 * |
|
3503 * @since 2.9.0 |
|
3504 * |
|
3505 * @param int $tt_id Term taxonomy ID. |
|
3506 * @param string $taxonomy Taxonomy slug. |
|
3507 */ |
2575 do_action( 'edit_term_taxonomy', $tt_id, $taxonomy ); |
3508 do_action( 'edit_term_taxonomy', $tt_id, $taxonomy ); |
2576 $wpdb->update( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent' ), array( 'term_taxonomy_id' => $tt_id ) ); |
3509 $wpdb->update( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent' ), array( 'term_taxonomy_id' => $tt_id ) ); |
|
3510 |
|
3511 /** |
|
3512 * Fires immediately after a term-taxonomy relationship is updated. |
|
3513 * |
|
3514 * @since 2.9.0 |
|
3515 * |
|
3516 * @param int $tt_id Term taxonomy ID. |
|
3517 * @param string $taxonomy Taxonomy slug. |
|
3518 */ |
2577 do_action( 'edited_term_taxonomy', $tt_id, $taxonomy ); |
3519 do_action( 'edited_term_taxonomy', $tt_id, $taxonomy ); |
2578 |
3520 |
2579 do_action("edit_term", $term_id, $tt_id, $taxonomy); |
3521 // Clean the relationship caches for all object types using this term |
2580 do_action("edit_$taxonomy", $term_id, $tt_id); |
3522 $objects = $wpdb->get_col( $wpdb->prepare( "SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $tt_id ) ); |
2581 |
3523 $tax_object = get_taxonomy( $taxonomy ); |
2582 $term_id = apply_filters('term_id_filter', $term_id, $tt_id); |
3524 foreach ( $tax_object->object_type as $object_type ) { |
|
3525 clean_object_term_cache( $objects, $object_type ); |
|
3526 } |
|
3527 |
|
3528 /** |
|
3529 * Fires after a term has been updated, but before the term cache has been cleaned. |
|
3530 * |
|
3531 * @since 2.3.0 |
|
3532 * |
|
3533 * @param int $term_id Term ID. |
|
3534 * @param int $tt_id Term taxonomy ID. |
|
3535 * @param string $taxonomy Taxonomy slug. |
|
3536 */ |
|
3537 do_action( "edit_term", $term_id, $tt_id, $taxonomy ); |
|
3538 |
|
3539 /** |
|
3540 * Fires after a term in a specific taxonomy has been updated, but before the term |
|
3541 * cache has been cleaned. |
|
3542 * |
|
3543 * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug. |
|
3544 * |
|
3545 * @since 2.3.0 |
|
3546 * |
|
3547 * @param int $term_id Term ID. |
|
3548 * @param int $tt_id Term taxonomy ID. |
|
3549 */ |
|
3550 do_action( "edit_$taxonomy", $term_id, $tt_id ); |
|
3551 |
|
3552 /** This filter is documented in wp-includes/taxonomy.php */ |
|
3553 $term_id = apply_filters( 'term_id_filter', $term_id, $tt_id ); |
2583 |
3554 |
2584 clean_term_cache($term_id, $taxonomy); |
3555 clean_term_cache($term_id, $taxonomy); |
2585 |
3556 |
2586 do_action("edited_term", $term_id, $tt_id, $taxonomy); |
3557 /** |
2587 do_action("edited_$taxonomy", $term_id, $tt_id); |
3558 * Fires after a term has been updated, and the term cache has been cleaned. |
|
3559 * |
|
3560 * @since 2.3.0 |
|
3561 * |
|
3562 * @param int $term_id Term ID. |
|
3563 * @param int $tt_id Term taxonomy ID. |
|
3564 * @param string $taxonomy Taxonomy slug. |
|
3565 */ |
|
3566 do_action( "edited_term", $term_id, $tt_id, $taxonomy ); |
|
3567 |
|
3568 /** |
|
3569 * Fires after a term for a specific taxonomy has been updated, and the term |
|
3570 * cache has been cleaned. |
|
3571 * |
|
3572 * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug. |
|
3573 * |
|
3574 * @since 2.3.0 |
|
3575 * |
|
3576 * @param int $term_id Term ID. |
|
3577 * @param int $tt_id Term taxonomy ID. |
|
3578 */ |
|
3579 do_action( "edited_$taxonomy", $term_id, $tt_id ); |
2588 |
3580 |
2589 return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id); |
3581 return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id); |
2590 } |
3582 } |
2591 |
3583 |
2592 /** |
3584 /** |
2767 } |
3760 } |
2768 } |
3761 } |
2769 } |
3762 } |
2770 |
3763 |
2771 foreach ( $taxonomies as $taxonomy ) { |
3764 foreach ( $taxonomies as $taxonomy ) { |
2772 if ( isset($cleaned[$taxonomy]) ) |
|
2773 continue; |
|
2774 $cleaned[$taxonomy] = true; |
|
2775 |
|
2776 if ( $clean_taxonomy ) { |
3765 if ( $clean_taxonomy ) { |
2777 wp_cache_delete('all_ids', $taxonomy); |
3766 wp_cache_delete('all_ids', $taxonomy); |
2778 wp_cache_delete('get', $taxonomy); |
3767 wp_cache_delete('get', $taxonomy); |
2779 delete_option("{$taxonomy}_children"); |
3768 delete_option("{$taxonomy}_children"); |
2780 // Regenerate {$taxonomy}_children |
3769 // Regenerate {$taxonomy}_children |
2781 _get_term_hierarchy($taxonomy); |
3770 _get_term_hierarchy($taxonomy); |
2782 } |
3771 } |
2783 |
3772 |
2784 do_action('clean_term_cache', $ids, $taxonomy); |
3773 /** |
|
3774 * Fires once after each taxonomy's term cache has been cleaned. |
|
3775 * |
|
3776 * @since 2.5.0 |
|
3777 * |
|
3778 * @param array $ids An array of term IDs. |
|
3779 * @param string $taxonomy Taxonomy slug. |
|
3780 */ |
|
3781 do_action( 'clean_term_cache', $ids, $taxonomy ); |
2785 } |
3782 } |
2786 |
3783 |
2787 wp_cache_set( 'last_changed', microtime(), 'terms' ); |
3784 wp_cache_set( 'last_changed', microtime(), 'terms' ); |
2788 } |
3785 } |
2789 |
3786 |
2790 /** |
3787 /** |
2791 * Retrieves the taxonomy relationship to the term object id. |
3788 * Retrieves the taxonomy relationship to the term object id. |
2792 * |
3789 * |
2793 * @package WordPress |
|
2794 * @subpackage Taxonomy |
|
2795 * @since 2.3.0 |
3790 * @since 2.3.0 |
2796 * |
3791 * |
2797 * @uses wp_cache_get() Retrieves taxonomy relationship from cache |
3792 * @param int $id Term object ID |
2798 * |
|
2799 * @param int|array $id Term object ID |
|
2800 * @param string $taxonomy Taxonomy Name |
3793 * @param string $taxonomy Taxonomy Name |
2801 * @return bool|array Empty array if $terms found, but not $taxonomy. False if nothing is in cache for $taxonomy and $id. |
3794 * @return bool|array Empty array if $terms found, but not $taxonomy. False if nothing is in cache for $taxonomy and $id. |
2802 */ |
3795 */ |
2803 function get_object_term_cache($id, $taxonomy) { |
3796 function get_object_term_cache($id, $taxonomy) { |
2804 $cache = wp_cache_get($id, "{$taxonomy}_relationships"); |
3797 $cache = wp_cache_get($id, "{$taxonomy}_relationships"); |
2805 return $cache; |
3798 return $cache; |
2806 } |
3799 } |
2807 |
3800 |
2808 /** |
3801 /** |
2809 * Updates the cache for Term ID(s). |
3802 * Updates the cache for the given term object ID(s). |
2810 * |
3803 * |
2811 * Will only update the cache for terms not already cached. |
3804 * Note: Due to performance concerns, great care should be taken to only update |
2812 * |
3805 * term caches when necessary. Processing time can increase exponentially depending |
2813 * The $object_ids expects that the ids be separated by commas, if it is a |
3806 * on both the number of passed term IDs and the number of taxonomies those terms |
2814 * string. |
3807 * belong to. |
2815 * |
3808 * |
2816 * It should be noted that update_object_term_cache() is very time extensive. It |
3809 * Caches will only be updated for terms not already cached. |
2817 * is advised that the function is not called very often or at least not for a |
3810 * |
2818 * lot of terms that exist in a lot of taxonomies. The amount of time increases |
|
2819 * for each term and it also increases for each taxonomy the term belongs to. |
|
2820 * |
|
2821 * @package WordPress |
|
2822 * @subpackage Taxonomy |
|
2823 * @since 2.3.0 |
3811 * @since 2.3.0 |
2824 * @uses wp_get_object_terms() Used to get terms from the database to update |
3812 * |
2825 * |
3813 * @param string|array $object_ids Comma-separated list or array of term object IDs.. |
2826 * @param string|array $object_ids Single or list of term object ID(s) |
3814 * @param array|string $object_type The taxonomy object type. |
2827 * @param array|string $object_type The taxonomy object type |
3815 * @return null|false Null if `$object_ids` is empty, false if all of the terms in |
2828 * @return null|bool Null value is given with empty $object_ids. False if |
3816 * `$object_ids` are already cached. |
2829 */ |
3817 */ |
2830 function update_object_term_cache($object_ids, $object_type) { |
3818 function update_object_term_cache($object_ids, $object_type) { |
2831 if ( empty($object_ids) ) |
3819 if ( empty($object_ids) ) |
2832 return; |
3820 return; |
2833 |
3821 |
2934 * Get the subset of $terms that are descendants of $term_id. |
3915 * Get the subset of $terms that are descendants of $term_id. |
2935 * |
3916 * |
2936 * If $terms is an array of objects, then _get_term_children returns an array of objects. |
3917 * If $terms is an array of objects, then _get_term_children returns an array of objects. |
2937 * If $terms is an array of IDs, then _get_term_children returns an array of IDs. |
3918 * If $terms is an array of IDs, then _get_term_children returns an array of IDs. |
2938 * |
3919 * |
2939 * @package WordPress |
|
2940 * @subpackage Taxonomy |
|
2941 * @access private |
3920 * @access private |
2942 * @since 2.3.0 |
3921 * @since 2.3.0 |
2943 * |
3922 * |
2944 * @param int $term_id The ancestor term: all returned terms should be descendants of $term_id. |
3923 * @param int $term_id The ancestor term: all returned terms should be descendants of $term_id. |
2945 * @param array $terms The set of terms---either an array of term objects or term IDs---from which those that are descendants of $term_id will be chosen. |
3924 * @param array $terms The set of terms - either an array of term objects or term IDs - from which those that |
2946 * @param string $taxonomy The taxonomy which determines the hierarchy of the terms. |
3925 * are descendants of $term_id will be chosen. |
|
3926 * @param string $taxonomy The taxonomy which determines the hierarchy of the terms. |
|
3927 * @param array $ancestors Term ancestors that have already been identified. Passed by reference, to keep track of |
|
3928 * found terms when recursing the hierarchy. The array of located ancestors is used to prevent |
|
3929 * infinite recursion loops. For performance, term_ids are used as array keys, with 1 as value. |
2947 * @return array The subset of $terms that are descendants of $term_id. |
3930 * @return array The subset of $terms that are descendants of $term_id. |
2948 */ |
3931 */ |
2949 function _get_term_children($term_id, $terms, $taxonomy) { |
3932 function _get_term_children( $term_id, $terms, $taxonomy, &$ancestors = array() ) { |
2950 $empty_array = array(); |
3933 $empty_array = array(); |
2951 if ( empty($terms) ) |
3934 if ( empty($terms) ) |
2952 return $empty_array; |
3935 return $empty_array; |
2953 |
3936 |
2954 $term_list = array(); |
3937 $term_list = array(); |
2955 $has_children = _get_term_hierarchy($taxonomy); |
3938 $has_children = _get_term_hierarchy($taxonomy); |
2956 |
3939 |
2957 if ( ( 0 != $term_id ) && ! isset($has_children[$term_id]) ) |
3940 if ( ( 0 != $term_id ) && ! isset($has_children[$term_id]) ) |
2958 return $empty_array; |
3941 return $empty_array; |
|
3942 |
|
3943 // Include the term itself in the ancestors array, so we can properly detect when a loop has occurred. |
|
3944 if ( empty( $ancestors ) ) { |
|
3945 $ancestors[ $term_id ] = 1; |
|
3946 } |
2959 |
3947 |
2960 foreach ( (array) $terms as $term ) { |
3948 foreach ( (array) $terms as $term ) { |
2961 $use_id = false; |
3949 $use_id = false; |
2962 if ( !is_object($term) ) { |
3950 if ( !is_object($term) ) { |
2963 $term = get_term($term, $taxonomy); |
3951 $term = get_term($term, $taxonomy); |
2964 if ( is_wp_error( $term ) ) |
3952 if ( is_wp_error( $term ) ) |
2965 return $term; |
3953 return $term; |
2966 $use_id = true; |
3954 $use_id = true; |
2967 } |
3955 } |
2968 |
3956 |
2969 if ( $term->term_id == $term_id ) |
3957 // Don't recurse if we've already identified the term as a child - this indicates a loop. |
|
3958 if ( isset( $ancestors[ $term->term_id ] ) ) { |
2970 continue; |
3959 continue; |
|
3960 } |
2971 |
3961 |
2972 if ( $term->parent == $term_id ) { |
3962 if ( $term->parent == $term_id ) { |
2973 if ( $use_id ) |
3963 if ( $use_id ) |
2974 $term_list[] = $term->term_id; |
3964 $term_list[] = $term->term_id; |
2975 else |
3965 else |
2976 $term_list[] = $term; |
3966 $term_list[] = $term; |
2977 |
3967 |
2978 if ( !isset($has_children[$term->term_id]) ) |
3968 if ( !isset($has_children[$term->term_id]) ) |
2979 continue; |
3969 continue; |
2980 |
3970 |
2981 if ( $children = _get_term_children($term->term_id, $terms, $taxonomy) ) |
3971 $ancestors[ $term->term_id ] = 1; |
|
3972 |
|
3973 if ( $children = _get_term_children( $term->term_id, $terms, $taxonomy, $ancestors) ) |
2982 $term_list = array_merge($term_list, $children); |
3974 $term_list = array_merge($term_list, $children); |
2983 } |
3975 } |
2984 } |
3976 } |
2985 |
3977 |
2986 return $term_list; |
3978 return $term_list; |
3093 $count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts p1 WHERE p1.ID = $wpdb->term_relationships.object_id AND ( post_status = 'publish' OR ( post_status = 'inherit' AND post_parent > 0 AND ( SELECT post_status FROM $wpdb->posts WHERE ID = p1.post_parent ) = 'publish' ) ) AND post_type = 'attachment' AND term_taxonomy_id = %d", $term ) ); |
4091 $count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts p1 WHERE p1.ID = $wpdb->term_relationships.object_id AND ( post_status = 'publish' OR ( post_status = 'inherit' AND post_parent > 0 AND ( SELECT post_status FROM $wpdb->posts WHERE ID = p1.post_parent ) = 'publish' ) ) AND post_type = 'attachment' AND term_taxonomy_id = %d", $term ) ); |
3094 |
4092 |
3095 if ( $object_types ) |
4093 if ( $object_types ) |
3096 $count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts WHERE $wpdb->posts.ID = $wpdb->term_relationships.object_id AND post_status = 'publish' AND post_type IN ('" . implode("', '", $object_types ) . "') AND term_taxonomy_id = %d", $term ) ); |
4094 $count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts WHERE $wpdb->posts.ID = $wpdb->term_relationships.object_id AND post_status = 'publish' AND post_type IN ('" . implode("', '", $object_types ) . "') AND term_taxonomy_id = %d", $term ) ); |
3097 |
4095 |
3098 do_action( 'edit_term_taxonomy', $term, $taxonomy ); |
4096 /** This action is documented in wp-includes/taxonomy.php */ |
|
4097 do_action( 'edit_term_taxonomy', $term, $taxonomy->name ); |
3099 $wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) ); |
4098 $wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) ); |
3100 do_action( 'edited_term_taxonomy', $term, $taxonomy ); |
4099 |
|
4100 /** This action is documented in wp-includes/taxonomy.php */ |
|
4101 do_action( 'edited_term_taxonomy', $term, $taxonomy->name ); |
3101 } |
4102 } |
3102 } |
4103 } |
3103 |
4104 |
3104 /** |
4105 /** |
3105 * Will update term count based on number of objects. |
4106 * Will update term count based on number of objects. |
3106 * |
4107 * |
3107 * Default callback for the link_category taxonomy. |
4108 * Default callback for the link_category taxonomy. |
3108 * |
4109 * |
3109 * @package WordPress |
|
3110 * @subpackage Taxonomy |
|
3111 * @since 3.3.0 |
4110 * @since 3.3.0 |
3112 * @uses $wpdb |
4111 * |
|
4112 * @global wpdb $wpdb WordPress database abstraction object. |
3113 * |
4113 * |
3114 * @param array $terms List of Term taxonomy IDs |
4114 * @param array $terms List of Term taxonomy IDs |
3115 * @param object $taxonomy Current taxonomy object of terms |
4115 * @param object $taxonomy Current taxonomy object of terms |
3116 */ |
4116 */ |
3117 function _update_generic_term_count( $terms, $taxonomy ) { |
4117 function _update_generic_term_count( $terms, $taxonomy ) { |
3118 global $wpdb; |
4118 global $wpdb; |
3119 |
4119 |
3120 foreach ( (array) $terms as $term ) { |
4120 foreach ( (array) $terms as $term ) { |
3121 $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $term ) ); |
4121 $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $term ) ); |
3122 |
4122 |
3123 do_action( 'edit_term_taxonomy', $term, $taxonomy ); |
4123 /** This action is documented in wp-includes/taxonomy.php */ |
|
4124 do_action( 'edit_term_taxonomy', $term, $taxonomy->name ); |
3124 $wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) ); |
4125 $wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) ); |
3125 do_action( 'edited_term_taxonomy', $term, $taxonomy ); |
4126 |
3126 } |
4127 /** This action is documented in wp-includes/taxonomy.php */ |
3127 } |
4128 do_action( 'edited_term_taxonomy', $term, $taxonomy->name ); |
3128 |
4129 } |
3129 /** |
4130 } |
3130 * Generates a permalink for a taxonomy term archive. |
4131 |
|
4132 /** |
|
4133 * Create a new term for a term_taxonomy item that currently shares its term with another term_taxonomy. |
|
4134 * |
|
4135 * @ignore |
|
4136 * @since 4.2.0 |
|
4137 * |
|
4138 * @param int $term_id ID of the shared term. |
|
4139 * @param int $term_taxonomy_id ID of the term_taxonomy item to receive a new term. |
|
4140 * @return int|WP_Error When the current term does not need to be split (or cannot be split on the current |
|
4141 * database schema), `$term_id` is returned. When the term is successfully split, the |
|
4142 * new term_id is returned. A WP_Error is returned for miscellaneous errors. |
|
4143 */ |
|
4144 function _split_shared_term( $term_id, $term_taxonomy_id ) { |
|
4145 global $wpdb; |
|
4146 |
|
4147 // Don't try to split terms if database schema does not support shared slugs. |
|
4148 $current_db_version = get_option( 'db_version' ); |
|
4149 if ( $current_db_version < 30133 ) { |
|
4150 return $term_id; |
|
4151 } |
|
4152 |
|
4153 // If there are no shared term_taxonomy rows, there's nothing to do here. |
|
4154 $shared_tt_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy tt WHERE tt.term_id = %d AND tt.term_taxonomy_id != %d", $term_id, $term_taxonomy_id ) ); |
|
4155 if ( ! $shared_tt_count ) { |
|
4156 return $term_id; |
|
4157 } |
|
4158 |
|
4159 // Pull up data about the currently shared slug, which we'll use to populate the new one. |
|
4160 $shared_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.* FROM $wpdb->terms t WHERE t.term_id = %d", $term_id ) ); |
|
4161 |
|
4162 $new_term_data = array( |
|
4163 'name' => $shared_term->name, |
|
4164 'slug' => $shared_term->slug, |
|
4165 'term_group' => $shared_term->term_group, |
|
4166 ); |
|
4167 |
|
4168 if ( false === $wpdb->insert( $wpdb->terms, $new_term_data ) ) { |
|
4169 return new WP_Error( 'db_insert_error', __( 'Could not split shared term.' ), $wpdb->last_error ); |
|
4170 } |
|
4171 |
|
4172 $new_term_id = (int) $wpdb->insert_id; |
|
4173 |
|
4174 // Update the existing term_taxonomy to point to the newly created term. |
|
4175 $wpdb->update( $wpdb->term_taxonomy, |
|
4176 array( 'term_id' => $new_term_id ), |
|
4177 array( 'term_taxonomy_id' => $term_taxonomy_id ) |
|
4178 ); |
|
4179 |
|
4180 // Reassign child terms to the new parent. |
|
4181 $term_taxonomy = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $term_taxonomy_id ) ); |
|
4182 $children_tt_ids = $wpdb->get_col( $wpdb->prepare( "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE taxonomy = %s AND parent = %d", $term_taxonomy->taxonomy, $term_id ) ); |
|
4183 |
|
4184 if ( ! empty( $children_tt_ids ) ) { |
|
4185 foreach ( $children_tt_ids as $child_tt_id ) { |
|
4186 $wpdb->update( $wpdb->term_taxonomy, |
|
4187 array( 'parent' => $new_term_id ), |
|
4188 array( 'term_taxonomy_id' => $child_tt_id ) |
|
4189 ); |
|
4190 clean_term_cache( $term_id, $term_taxonomy->taxonomy ); |
|
4191 } |
|
4192 } else { |
|
4193 // If the term has no children, we must force its taxonomy cache to be rebuilt separately. |
|
4194 clean_term_cache( $new_term_id, $term_taxonomy->taxonomy ); |
|
4195 } |
|
4196 |
|
4197 // Clean the cache for term taxonomies formerly shared with the current term. |
|
4198 $shared_term_taxonomies = $wpdb->get_row( $wpdb->prepare( "SELECT taxonomy FROM $wpdb->term_taxonomy WHERE term_id = %d", $term_id ) ); |
|
4199 if ( $shared_term_taxonomies ) { |
|
4200 foreach ( $shared_term_taxonomies as $shared_term_taxonomy ) { |
|
4201 clean_term_cache( $term_id, $shared_term_taxonomy ); |
|
4202 } |
|
4203 } |
|
4204 |
|
4205 // Keep a record of term_ids that have been split, keyed by old term_id. See {@see wp_get_split_term()}. |
|
4206 $split_term_data = get_option( '_split_terms', array() ); |
|
4207 if ( ! isset( $split_term_data[ $term_id ] ) ) { |
|
4208 $split_term_data[ $term_id ] = array(); |
|
4209 } |
|
4210 |
|
4211 $split_term_data[ $term_id ][ $term_taxonomy->taxonomy ] = $new_term_id; |
|
4212 |
|
4213 update_option( '_split_terms', $split_term_data ); |
|
4214 |
|
4215 /** |
|
4216 * Fires after a previously shared taxonomy term is split into two separate terms. |
|
4217 * |
|
4218 * @since 4.2.0 |
|
4219 * |
|
4220 * @param int $term_id ID of the formerly shared term. |
|
4221 * @param int $new_term_id ID of the new term created for the $term_taxonomy_id. |
|
4222 * @param int $term_taxonomy_id ID for the term_taxonomy row affected by the split. |
|
4223 * @param string $taxonomy Taxonomy for the split term. |
|
4224 */ |
|
4225 do_action( 'split_shared_term', $term_id, $new_term_id, $term_taxonomy_id, $term_taxonomy->taxonomy ); |
|
4226 |
|
4227 return $new_term_id; |
|
4228 } |
|
4229 |
|
4230 /** |
|
4231 * Check default categories when a term gets split to see if any of them need to be updated. |
|
4232 * |
|
4233 * @ignore |
|
4234 * @since 4.2.0 |
|
4235 * |
|
4236 * @param int $term_id ID of the formerly shared term. |
|
4237 * @param int $new_term_id ID of the new term created for the $term_taxonomy_id. |
|
4238 * @param int $term_taxonomy_id ID for the term_taxonomy row affected by the split. |
|
4239 * @param string $taxonomy Taxonomy for the split term. |
|
4240 */ |
|
4241 function _wp_check_split_default_terms( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) { |
|
4242 if ( 'category' != $taxonomy ) { |
|
4243 return; |
|
4244 } |
|
4245 |
|
4246 foreach ( array( 'default_category', 'default_link_category', 'default_email_category' ) as $option ) { |
|
4247 if ( $term_id == get_option( $option, -1 ) ) { |
|
4248 update_option( $option, $new_term_id ); |
|
4249 } |
|
4250 } |
|
4251 } |
|
4252 |
|
4253 /** |
|
4254 * Check menu items when a term gets split to see if any of them need to be updated. |
|
4255 * |
|
4256 * @ignore |
|
4257 * @since 4.2.0 |
|
4258 * |
|
4259 * @param int $term_id ID of the formerly shared term. |
|
4260 * @param int $new_term_id ID of the new term created for the $term_taxonomy_id. |
|
4261 * @param int $term_taxonomy_id ID for the term_taxonomy row affected by the split. |
|
4262 * @param string $taxonomy Taxonomy for the split term. |
|
4263 */ |
|
4264 function _wp_check_split_terms_in_menus( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) { |
|
4265 global $wpdb; |
|
4266 $post_ids = $wpdb->get_col( $wpdb->prepare( |
|
4267 "SELECT m1.post_id |
|
4268 FROM {$wpdb->postmeta} AS m1 |
|
4269 INNER JOIN {$wpdb->postmeta} AS m2 ON ( m2.post_id = m1.post_id ) |
|
4270 INNER JOIN {$wpdb->postmeta} AS m3 ON ( m3.post_id = m1.post_id ) |
|
4271 WHERE ( m1.meta_key = '_menu_item_type' AND m1.meta_value = 'taxonomy' ) |
|
4272 AND ( m2.meta_key = '_menu_item_object' AND m2.meta_value = '%s' ) |
|
4273 AND ( m3.meta_key = '_menu_item_object_id' AND m3.meta_value = %d )", |
|
4274 $taxonomy, |
|
4275 $term_id |
|
4276 ) ); |
|
4277 |
|
4278 if ( $post_ids ) { |
|
4279 foreach ( $post_ids as $post_id ) { |
|
4280 update_post_meta( $post_id, '_menu_item_object_id', $new_term_id, $term_id ); |
|
4281 } |
|
4282 } |
|
4283 } |
|
4284 |
|
4285 /** |
|
4286 * Get data about terms that previously shared a single term_id, but have since been split. |
|
4287 * |
|
4288 * @since 4.2.0 |
|
4289 * |
|
4290 * @param int $old_term_id Term ID. This is the old, pre-split term ID. |
|
4291 * @return array Array of new term IDs, keyed by taxonomy. |
|
4292 */ |
|
4293 function wp_get_split_terms( $old_term_id ) { |
|
4294 $split_terms = get_option( '_split_terms', array() ); |
|
4295 |
|
4296 $terms = array(); |
|
4297 if ( isset( $split_terms[ $old_term_id ] ) ) { |
|
4298 $terms = $split_terms[ $old_term_id ]; |
|
4299 } |
|
4300 |
|
4301 return $terms; |
|
4302 } |
|
4303 |
|
4304 /** |
|
4305 * Get the new term ID corresponding to a previously split term. |
|
4306 * |
|
4307 * @since 4.2.0 |
|
4308 * |
|
4309 * @param int $old_term_id Term ID. This is the old, pre-split term ID. |
|
4310 * @param string $taxonomy Taxonomy that the term belongs to. |
|
4311 * @return bool|int If a previously split term is found corresponding to the old term_id and taxonomy, |
|
4312 * the new term_id will be returned. If no previously split term is found matching |
|
4313 * the parameters, returns false. |
|
4314 */ |
|
4315 function wp_get_split_term( $old_term_id, $taxonomy ) { |
|
4316 $split_terms = wp_get_split_terms( $old_term_id ); |
|
4317 |
|
4318 $term_id = false; |
|
4319 if ( isset( $split_terms[ $taxonomy ] ) ) { |
|
4320 $term_id = (int) $split_terms[ $taxonomy ]; |
|
4321 } |
|
4322 |
|
4323 return $term_id; |
|
4324 } |
|
4325 |
|
4326 /** |
|
4327 * Generate a permalink for a taxonomy term archive. |
3131 * |
4328 * |
3132 * @since 2.5.0 |
4329 * @since 2.5.0 |
3133 * |
4330 * |
3134 * @uses apply_filters() Calls 'term_link' with term link and term object, and taxonomy parameters. |
4331 * @param object|int|string $term The term object, ID, or slug whose link will be retrieved. |
3135 * @uses apply_filters() For the post_tag Taxonomy, Calls 'tag_link' with tag link and tag ID as parameters. |
4332 * @param string $taxonomy Optional. Taxonomy. Default empty. |
3136 * @uses apply_filters() For the category Taxonomy, Calls 'category_link' filter on category link and category ID. |
|
3137 * |
|
3138 * @param object|int|string $term |
|
3139 * @param string $taxonomy (optional if $term is object) |
|
3140 * @return string|WP_Error HTML link to taxonomy term archive on success, WP_Error if term does not exist. |
4333 * @return string|WP_Error HTML link to taxonomy term archive on success, WP_Error if term does not exist. |
3141 */ |
4334 */ |
3142 function get_term_link( $term, $taxonomy = '') { |
4335 function get_term_link( $term, $taxonomy = '') { |
3143 global $wp_rewrite; |
4336 global $wp_rewrite; |
3144 |
4337 |
3186 $termlink = str_replace("%$taxonomy%", $slug, $termlink); |
4379 $termlink = str_replace("%$taxonomy%", $slug, $termlink); |
3187 } |
4380 } |
3188 $termlink = home_url( user_trailingslashit($termlink, 'category') ); |
4381 $termlink = home_url( user_trailingslashit($termlink, 'category') ); |
3189 } |
4382 } |
3190 // Back Compat filters. |
4383 // Back Compat filters. |
3191 if ( 'post_tag' == $taxonomy ) |
4384 if ( 'post_tag' == $taxonomy ) { |
|
4385 |
|
4386 /** |
|
4387 * Filter the tag link. |
|
4388 * |
|
4389 * @since 2.3.0 |
|
4390 * @deprecated 2.5.0 Use 'term_link' instead. |
|
4391 * |
|
4392 * @param string $termlink Tag link URL. |
|
4393 * @param int $term_id Term ID. |
|
4394 */ |
3192 $termlink = apply_filters( 'tag_link', $termlink, $term->term_id ); |
4395 $termlink = apply_filters( 'tag_link', $termlink, $term->term_id ); |
3193 elseif ( 'category' == $taxonomy ) |
4396 } elseif ( 'category' == $taxonomy ) { |
|
4397 |
|
4398 /** |
|
4399 * Filter the category link. |
|
4400 * |
|
4401 * @since 1.5.0 |
|
4402 * @deprecated 2.5.0 Use 'term_link' instead. |
|
4403 * |
|
4404 * @param string $termlink Category link URL. |
|
4405 * @param int $term_id Term ID. |
|
4406 */ |
3194 $termlink = apply_filters( 'category_link', $termlink, $term->term_id ); |
4407 $termlink = apply_filters( 'category_link', $termlink, $term->term_id ); |
3195 |
4408 } |
3196 return apply_filters('term_link', $termlink, $term, $taxonomy); |
4409 |
|
4410 /** |
|
4411 * Filter the term link. |
|
4412 * |
|
4413 * @since 2.5.0 |
|
4414 * |
|
4415 * @param string $termlink Term link URL. |
|
4416 * @param object $term Term object. |
|
4417 * @param string $taxonomy Taxonomy slug. |
|
4418 */ |
|
4419 return apply_filters( 'term_link', $termlink, $term, $taxonomy ); |
3197 } |
4420 } |
3198 |
4421 |
3199 /** |
4422 /** |
3200 * Display the taxonomies of a post with available options. |
4423 * Display the taxonomies of a post with available options. |
3201 * |
4424 * |
3202 * This function can be used within the loop to display the taxonomies for a |
4425 * This function can be used within the loop to display the taxonomies for a |
3203 * post without specifying the Post ID. You can also use it outside the Loop to |
4426 * post without specifying the Post ID. You can also use it outside the Loop to |
3204 * display the taxonomies for a specific post. |
4427 * display the taxonomies for a specific post. |
3205 * |
4428 * |
3206 * The available defaults are: |
|
3207 * 'post' : default is 0. The post ID to get taxonomies of. |
|
3208 * 'before' : default is empty string. Display before taxonomies list. |
|
3209 * 'sep' : default is empty string. Separate every taxonomy with value in this. |
|
3210 * 'after' : default is empty string. Display this after the taxonomies list. |
|
3211 * 'template' : The template to use for displaying the taxonomy terms. |
|
3212 * |
|
3213 * @since 2.5.0 |
4429 * @since 2.5.0 |
3214 * @uses get_the_taxonomies() |
4430 * |
3215 * |
4431 * @param array $args { |
3216 * @param array $args Override the defaults. |
4432 * Arguments about which post to use and how to format the output. Shares all of the arguments supported by |
3217 */ |
4433 * {@link get_the_taxonomies()}, in addition to the following. |
3218 function the_taxonomies($args = array()) { |
4434 * |
|
4435 * @type int|WP_Post $post Post ID or object to get taxonomies of. Default current post. |
|
4436 * @type string $before Displays before the taxonomies. Default empty string. |
|
4437 * @type string $sep Separates each taxonomy. Default is a space. |
|
4438 * @type string $after Displays after the taxonomies. Default empty string. |
|
4439 * } |
|
4440 * @param array $args See {@link get_the_taxonomies()} for a description of arguments and their defaults. |
|
4441 */ |
|
4442 function the_taxonomies( $args = array() ) { |
3219 $defaults = array( |
4443 $defaults = array( |
3220 'post' => 0, |
4444 'post' => 0, |
3221 'before' => '', |
4445 'before' => '', |
3222 'sep' => ' ', |
4446 'sep' => ' ', |
3223 'after' => '', |
4447 'after' => '', |
3224 'template' => '%s: %l.' |
|
3225 ); |
4448 ); |
3226 |
4449 |
3227 $r = wp_parse_args( $args, $defaults ); |
4450 $r = wp_parse_args( $args, $defaults ); |
3228 extract( $r, EXTR_SKIP ); |
4451 |
3229 |
4452 echo $r['before'] . join( $r['sep'], get_the_taxonomies( $r['post'], $r ) ) . $r['after']; |
3230 echo $before . join($sep, get_the_taxonomies($post, $r)) . $after; |
|
3231 } |
4453 } |
3232 |
4454 |
3233 /** |
4455 /** |
3234 * Retrieve all taxonomies associated with a post. |
4456 * Retrieve all taxonomies associated with a post. |
3235 * |
4457 * |
3236 * This function can be used within the loop. It will also return an array of |
4458 * This function can be used within the loop. It will also return an array of |
3237 * the taxonomies with links to the taxonomy and name. |
4459 * the taxonomies with links to the taxonomy and name. |
3238 * |
4460 * |
3239 * @since 2.5.0 |
4461 * @since 2.5.0 |
3240 * |
4462 * |
3241 * @param int $post Optional. Post ID or will use Global Post ID (in loop). |
4463 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. |
3242 * @param array $args Override the defaults. |
4464 * @param array $args { |
|
4465 * Arguments about how to format the list of taxonomies. |
|
4466 * |
|
4467 * @type string $template Template for displaying a taxonomy label and list of terms. |
|
4468 * Default is "Label: Terms." |
|
4469 * @type string $term_template Template for displaying a single term in the list. Default is the term name |
|
4470 * linked to its archive. |
|
4471 * } |
|
4472 * @return array List of taxonomies. |
|
4473 */ |
|
4474 function get_the_taxonomies( $post = 0, $args = array() ) { |
|
4475 $post = get_post( $post ); |
|
4476 |
|
4477 $args = wp_parse_args( $args, array( |
|
4478 /* translators: %s: taxonomy label, %l: list of terms formatted as per $term_template */ |
|
4479 'template' => __( '%s: %l.' ), |
|
4480 'term_template' => '<a href="%1$s">%2$s</a>', |
|
4481 ) ); |
|
4482 |
|
4483 $taxonomies = array(); |
|
4484 |
|
4485 if ( ! $post ) { |
|
4486 return $taxonomies; |
|
4487 } |
|
4488 |
|
4489 foreach ( get_object_taxonomies( $post ) as $taxonomy ) { |
|
4490 $t = (array) get_taxonomy( $taxonomy ); |
|
4491 if ( empty( $t['label'] ) ) { |
|
4492 $t['label'] = $taxonomy; |
|
4493 } |
|
4494 if ( empty( $t['args'] ) ) { |
|
4495 $t['args'] = array(); |
|
4496 } |
|
4497 if ( empty( $t['template'] ) ) { |
|
4498 $t['template'] = $args['template']; |
|
4499 } |
|
4500 if ( empty( $t['term_template'] ) ) { |
|
4501 $t['term_template'] = $args['term_template']; |
|
4502 } |
|
4503 |
|
4504 $terms = get_object_term_cache( $post->ID, $taxonomy ); |
|
4505 if ( false === $terms ) { |
|
4506 $terms = wp_get_object_terms( $post->ID, $taxonomy, $t['args'] ); |
|
4507 } |
|
4508 $links = array(); |
|
4509 |
|
4510 foreach ( $terms as $term ) { |
|
4511 $links[] = wp_sprintf( $t['term_template'], esc_attr( get_term_link( $term ) ), $term->name ); |
|
4512 } |
|
4513 if ( $links ) { |
|
4514 $taxonomies[$taxonomy] = wp_sprintf( $t['template'], $t['label'], $links, $terms ); |
|
4515 } |
|
4516 } |
|
4517 return $taxonomies; |
|
4518 } |
|
4519 |
|
4520 /** |
|
4521 * Retrieve all taxonomies of a post with just the names. |
|
4522 * |
|
4523 * @since 2.5.0 |
|
4524 * |
|
4525 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. |
3243 * @return array |
4526 * @return array |
3244 */ |
4527 */ |
3245 function get_the_taxonomies($post = 0, $args = array() ) { |
4528 function get_post_taxonomies( $post = 0 ) { |
3246 $post = get_post( $post ); |
|
3247 |
|
3248 $args = wp_parse_args( $args, array( |
|
3249 'template' => '%s: %l.', |
|
3250 ) ); |
|
3251 extract( $args, EXTR_SKIP ); |
|
3252 |
|
3253 $taxonomies = array(); |
|
3254 |
|
3255 if ( !$post ) |
|
3256 return $taxonomies; |
|
3257 |
|
3258 foreach ( get_object_taxonomies($post) as $taxonomy ) { |
|
3259 $t = (array) get_taxonomy($taxonomy); |
|
3260 if ( empty($t['label']) ) |
|
3261 $t['label'] = $taxonomy; |
|
3262 if ( empty($t['args']) ) |
|
3263 $t['args'] = array(); |
|
3264 if ( empty($t['template']) ) |
|
3265 $t['template'] = $template; |
|
3266 |
|
3267 $terms = get_object_term_cache($post->ID, $taxonomy); |
|
3268 if ( false === $terms ) |
|
3269 $terms = wp_get_object_terms($post->ID, $taxonomy, $t['args']); |
|
3270 |
|
3271 $links = array(); |
|
3272 |
|
3273 foreach ( $terms as $term ) |
|
3274 $links[] = "<a href='" . esc_attr( get_term_link($term) ) . "'>$term->name</a>"; |
|
3275 |
|
3276 if ( $links ) |
|
3277 $taxonomies[$taxonomy] = wp_sprintf($t['template'], $t['label'], $links, $terms); |
|
3278 } |
|
3279 return $taxonomies; |
|
3280 } |
|
3281 |
|
3282 /** |
|
3283 * Retrieve all taxonomies of a post with just the names. |
|
3284 * |
|
3285 * @since 2.5.0 |
|
3286 * @uses get_object_taxonomies() |
|
3287 * |
|
3288 * @param int $post Optional. Post ID |
|
3289 * @return array |
|
3290 */ |
|
3291 function get_post_taxonomies($post = 0) { |
|
3292 $post = get_post( $post ); |
4529 $post = get_post( $post ); |
3293 |
4530 |
3294 return get_object_taxonomies($post); |
4531 return get_object_taxonomies($post); |
3295 } |
4532 } |
3296 |
4533 |