/sandbox/wp-includes/taxonomy.php
PHP | 4722 lines | 2190 code | 604 blank | 1928 comment | 541 complexity | 8ff69b032f99c10cdcd99080fc394a31 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- <?php
- /**
- * Taxonomy API
- *
- * @package WordPress
- * @subpackage Taxonomy
- * @since 2.3.0
- */
- //
- // Taxonomy Registration
- //
- /**
- * Creates the initial taxonomies.
- *
- * This function fires twice: in wp-settings.php before plugins are loaded (for
- * backwards compatibility reasons), and again on the 'init' action. We must avoid
- * registering rewrite rules before the 'init' action.
- */
- function create_initial_taxonomies() {
- global $wp_rewrite;
- if ( ! did_action( 'init' ) ) {
- $rewrite = array( 'category' => false, 'post_tag' => false, 'post_format' => false );
- } else {
- /**
- * Filter the post formats rewrite base.
- *
- * @since 3.1.0
- *
- * @param string $context Context of the rewrite base. Default 'type'.
- */
- $post_format_base = apply_filters( 'post_format_rewrite_base', 'type' );
- $rewrite = array(
- 'category' => array(
- 'hierarchical' => true,
- 'slug' => get_option('category_base') ? get_option('category_base') : 'category',
- 'with_front' => ! get_option('category_base') || $wp_rewrite->using_index_permalinks(),
- 'ep_mask' => EP_CATEGORIES,
- ),
- 'post_tag' => array(
- 'hierarchical' => false,
- 'slug' => get_option('tag_base') ? get_option('tag_base') : 'tag',
- 'with_front' => ! get_option('tag_base') || $wp_rewrite->using_index_permalinks(),
- 'ep_mask' => EP_TAGS,
- ),
- 'post_format' => $post_format_base ? array( 'slug' => $post_format_base ) : false,
- );
- }
- register_taxonomy( 'category', 'post', array(
- 'hierarchical' => true,
- 'query_var' => 'category_name',
- 'rewrite' => $rewrite['category'],
- 'public' => true,
- 'show_ui' => true,
- 'show_admin_column' => true,
- '_builtin' => true,
- ) );
- register_taxonomy( 'post_tag', 'post', array(
- 'hierarchical' => false,
- 'query_var' => 'tag',
- 'rewrite' => $rewrite['post_tag'],
- 'public' => true,
- 'show_ui' => true,
- 'show_admin_column' => true,
- '_builtin' => true,
- ) );
- register_taxonomy( 'nav_menu', 'nav_menu_item', array(
- 'public' => false,
- 'hierarchical' => false,
- 'labels' => array(
- 'name' => __( 'Navigation Menus' ),
- 'singular_name' => __( 'Navigation Menu' ),
- ),
- 'query_var' => false,
- 'rewrite' => false,
- 'show_ui' => false,
- '_builtin' => true,
- 'show_in_nav_menus' => false,
- ) );
- register_taxonomy( 'link_category', 'link', array(
- 'hierarchical' => false,
- 'labels' => array(
- 'name' => __( 'Link Categories' ),
- 'singular_name' => __( 'Link Category' ),
- 'search_items' => __( 'Search Link Categories' ),
- 'popular_items' => null,
- 'all_items' => __( 'All Link Categories' ),
- 'edit_item' => __( 'Edit Link Category' ),
- 'update_item' => __( 'Update Link Category' ),
- 'add_new_item' => __( 'Add New Link Category' ),
- 'new_item_name' => __( 'New Link Category Name' ),
- 'separate_items_with_commas' => null,
- 'add_or_remove_items' => null,
- 'choose_from_most_used' => null,
- ),
- 'capabilities' => array(
- 'manage_terms' => 'manage_links',
- 'edit_terms' => 'manage_links',
- 'delete_terms' => 'manage_links',
- 'assign_terms' => 'manage_links',
- ),
- 'query_var' => false,
- 'rewrite' => false,
- 'public' => false,
- 'show_ui' => false,
- '_builtin' => true,
- ) );
- register_taxonomy( 'post_format', 'post', array(
- 'public' => true,
- 'hierarchical' => false,
- 'labels' => array(
- 'name' => _x( 'Format', 'post format' ),
- 'singular_name' => _x( 'Format', 'post format' ),
- ),
- 'query_var' => true,
- 'rewrite' => $rewrite['post_format'],
- 'show_ui' => false,
- '_builtin' => true,
- 'show_in_nav_menus' => current_theme_supports( 'post-formats' ),
- ) );
- }
- /**
- * Get a list of registered taxonomy objects.
- *
- * @since 3.0.0
- * @uses $wp_taxonomies
- *
- * @param array $args An array of key => value arguments to match against the taxonomy objects.
- * @param string $output The type of output to return, either taxonomy 'names' or 'objects'. 'names' is the default.
- * @param string $operator The logical operation to perform. 'or' means only one element
- * from the array needs to match; 'and' means all elements must match. The default is 'and'.
- * @return array A list of taxonomy names or objects
- */
- function get_taxonomies( $args = array(), $output = 'names', $operator = 'and' ) {
- global $wp_taxonomies;
- $field = ('names' == $output) ? 'name' : false;
- return wp_filter_object_list($wp_taxonomies, $args, $operator, $field);
- }
- /**
- * Return all of the taxonomy names that are of $object_type.
- *
- * It appears that this function can be used to find all of the names inside of
- * $wp_taxonomies global variable.
- *
- * `<?php $taxonomies = get_object_taxonomies('post'); ?>` Should
- * result in `Array( 'category', 'post_tag' )`
- *
- * @since 2.3.0
- *
- * @uses $wp_taxonomies
- *
- * @param array|string|object $object Name of the type of taxonomy object, or an object (row from posts)
- * @param string $output The type of output to return, either taxonomy 'names' or 'objects'. 'names' is the default.
- * @return array The names of all taxonomy of $object_type.
- */
- function get_object_taxonomies($object, $output = 'names') {
- global $wp_taxonomies;
- if ( is_object($object) ) {
- if ( $object->post_type == 'attachment' )
- return get_attachment_taxonomies($object);
- $object = $object->post_type;
- }
- $object = (array) $object;
- $taxonomies = array();
- foreach ( (array) $wp_taxonomies as $tax_name => $tax_obj ) {
- if ( array_intersect($object, (array) $tax_obj->object_type) ) {
- if ( 'names' == $output )
- $taxonomies[] = $tax_name;
- else
- $taxonomies[ $tax_name ] = $tax_obj;
- }
- }
- return $taxonomies;
- }
- /**
- * Retrieves the taxonomy object of $taxonomy.
- *
- * The get_taxonomy function will first check that the parameter string given
- * is a taxonomy object and if it is, it will return it.
- *
- * @since 2.3.0
- *
- * @uses $wp_taxonomies
- *
- * @param string $taxonomy Name of taxonomy object to return
- * @return object|bool The Taxonomy Object or false if $taxonomy doesn't exist
- */
- function get_taxonomy( $taxonomy ) {
- global $wp_taxonomies;
- if ( ! taxonomy_exists( $taxonomy ) )
- return false;
- return $wp_taxonomies[$taxonomy];
- }
- /**
- * Checks that the taxonomy name exists.
- *
- * Formerly is_taxonomy(), introduced in 2.3.0.
- *
- * @since 3.0.0
- *
- * @uses $wp_taxonomies
- *
- * @param string $taxonomy Name of taxonomy object
- * @return bool Whether the taxonomy exists.
- */
- function taxonomy_exists( $taxonomy ) {
- global $wp_taxonomies;
- return isset( $wp_taxonomies[$taxonomy] );
- }
- /**
- * Whether the taxonomy object is hierarchical.
- *
- * Checks to make sure that the taxonomy is an object first. Then Gets the
- * object, and finally returns the hierarchical value in the object.
- *
- * A false return value might also mean that the taxonomy does not exist.
- *
- * @since 2.3.0
- *
- * @param string $taxonomy Name of taxonomy object
- * @return bool Whether the taxonomy is hierarchical
- */
- function is_taxonomy_hierarchical($taxonomy) {
- if ( ! taxonomy_exists($taxonomy) )
- return false;
- $taxonomy = get_taxonomy($taxonomy);
- return $taxonomy->hierarchical;
- }
- /**
- * Create or modify a taxonomy object. Do not use before init.
- *
- * A simple function for creating or modifying a taxonomy object based on the
- * parameters given. The function will accept an array (third optional
- * parameter), along with strings for the taxonomy name and another string for
- * the object type.
- *
- * Nothing is returned, so expect error maybe or use taxonomy_exists() to check
- * whether taxonomy exists.
- *
- * Optional $args contents:
- *
- * - label - Name of the taxonomy shown in the menu. Usually plural. If not set, labels['name'] will be used.
- * - labels - An array of labels for this taxonomy.
- * * By default tag labels are used for non-hierarchical types and category labels for hierarchical ones.
- * * You can see accepted values in {@link get_taxonomy_labels()}.
- * - description - A short descriptive summary of what the taxonomy is for. Defaults to blank.
- * - public - If the taxonomy should be publicly queryable; //@TODO not implemented.
- * * Defaults to true.
- * - hierarchical - Whether the taxonomy is hierarchical (e.g. category). Defaults to false.
- * - show_ui - Whether to generate a default UI for managing this taxonomy in the admin.
- * * If not set, the default is inherited from public.
- * - show_in_menu - Whether to show the taxonomy in the admin menu.
- * * If true, the taxonomy is shown as a submenu of the object type menu.
- * * If false, no menu is shown.
- * * show_ui must be true.
- * * If not set, the default is inherited from show_ui.
- * - show_in_nav_menus - Makes this taxonomy available for selection in navigation menus.
- * * If not set, the default is inherited from public.
- * - show_tagcloud - Whether to list the taxonomy in the Tag Cloud Widget.
- * * If not set, the default is inherited from show_ui.
- * - show_in_quick_edit - Whether to show the taxonomy in the quick/bulk edit panel.
- * * It not set, the default is inherited from show_ui.
- * - show_admin_column - Whether to display a column for the taxonomy on its post type listing screens.
- * * Defaults to false.
- * - meta_box_cb - Provide a callback function for the meta box display.
- * * If not set, defaults to post_categories_meta_box for hierarchical taxonomies
- * and post_tags_meta_box for non-hierarchical.
- * * If false, no meta box is shown.
- * - capabilities - Array of capabilities for this taxonomy.
- * * You can see accepted values in this function.
- * - rewrite - Triggers the handling of rewrites for this taxonomy. Defaults to true, using $taxonomy as slug.
- * * To prevent rewrite, set to false.
- * * To specify rewrite rules, an array can be passed with any of these keys
- * * 'slug' => string Customize the permastruct slug. Defaults to $taxonomy key
- * * 'with_front' => bool Should the permastruct be prepended with WP_Rewrite::$front. Defaults to true.
- * * 'hierarchical' => bool Either hierarchical rewrite tag or not. Defaults to false.
- * * 'ep_mask' => const Assign an endpoint mask.
- * * If not specified, defaults to EP_NONE.
- * - query_var - Sets the query_var key for this taxonomy. Defaults to $taxonomy key
- * * If false, a taxonomy cannot be loaded at ?{query_var}={term_slug}
- * * If specified as a string, the query ?{query_var_string}={term_slug} will be valid.
- * - update_count_callback - Works much like a hook, in that it will be called when the count is updated.
- * * Defaults to _update_post_term_count() for taxonomies attached to post types, which then confirms
- * that the objects are published before counting them.
- * * Defaults to _update_generic_term_count() for taxonomies attached to other object types, such as links.
- * - _builtin - true if this taxonomy is a native or "built-in" taxonomy. THIS IS FOR INTERNAL USE ONLY!
- *
- * @since 2.3.0
- * @since 4.2.0 Introduced `show_in_quick_edit` argument.
- *
- * @global array $wp_taxonomies Registered taxonomies.
- * @global WP $wp WP instance.
- *
- * @param string $taxonomy Taxonomy key, must not exceed 32 characters.
- * @param array|string $object_type Name of the object type for the taxonomy object.
- * @param array|string $args See optional args description above.
- * @return null|WP_Error WP_Error if errors, otherwise null.
- */
- function register_taxonomy( $taxonomy, $object_type, $args = array() ) {
- global $wp_taxonomies, $wp;
- if ( ! is_array( $wp_taxonomies ) )
- $wp_taxonomies = array();
- $defaults = array(
- 'labels' => array(),
- 'description' => '',
- 'public' => true,
- 'hierarchical' => false,
- 'show_ui' => null,
- 'show_in_menu' => null,
- 'show_in_nav_menus' => null,
- 'show_tagcloud' => null,
- 'show_in_quick_edit' => null,
- 'show_admin_column' => false,
- 'meta_box_cb' => null,
- 'capabilities' => array(),
- 'rewrite' => true,
- 'query_var' => $taxonomy,
- 'update_count_callback' => '',
- '_builtin' => false,
- );
- $args = wp_parse_args( $args, $defaults );
- if ( empty( $taxonomy ) || strlen( $taxonomy ) > 32 ) {
- _doing_it_wrong( __FUNCTION__, __( 'Taxonomy names must be between 1 and 32 characters in length.' ), '4.2' );
- return new WP_Error( 'taxonomy_length_invalid', __( 'Taxonomy names must be between 1 and 32 characters in length.' ) );
- }
- if ( false !== $args['query_var'] && ! empty( $wp ) ) {
- if ( true === $args['query_var'] )
- $args['query_var'] = $taxonomy;
- else
- $args['query_var'] = sanitize_title_with_dashes( $args['query_var'] );
- $wp->add_query_var( $args['query_var'] );
- }
- if ( false !== $args['rewrite'] && ( is_admin() || '' != get_option( 'permalink_structure' ) ) ) {
- $args['rewrite'] = wp_parse_args( $args['rewrite'], array(
- 'with_front' => true,
- 'hierarchical' => false,
- 'ep_mask' => EP_NONE,
- ) );
- if ( empty( $args['rewrite']['slug'] ) )
- $args['rewrite']['slug'] = sanitize_title_with_dashes( $taxonomy );
- if ( $args['hierarchical'] && $args['rewrite']['hierarchical'] )
- $tag = '(.+?)';
- else
- $tag = '([^/]+)';
- add_rewrite_tag( "%$taxonomy%", $tag, $args['query_var'] ? "{$args['query_var']}=" : "taxonomy=$taxonomy&term=" );
- add_permastruct( $taxonomy, "{$args['rewrite']['slug']}/%$taxonomy%", $args['rewrite'] );
- }
- // If not set, default to the setting for public.
- if ( null === $args['show_ui'] )
- $args['show_ui'] = $args['public'];
- // If not set, default to the setting for show_ui.
- if ( null === $args['show_in_menu' ] || ! $args['show_ui'] )
- $args['show_in_menu' ] = $args['show_ui'];
- // If not set, default to the setting for public.
- if ( null === $args['show_in_nav_menus'] )
- $args['show_in_nav_menus'] = $args['public'];
- // If not set, default to the setting for show_ui.
- if ( null === $args['show_tagcloud'] )
- $args['show_tagcloud'] = $args['show_ui'];
- // If not set, default to the setting for show_ui.
- if ( null === $args['show_in_quick_edit'] ) {
- $args['show_in_quick_edit'] = $args['show_ui'];
- }
- $default_caps = array(
- 'manage_terms' => 'manage_categories',
- 'edit_terms' => 'manage_categories',
- 'delete_terms' => 'manage_categories',
- 'assign_terms' => 'edit_posts',
- );
- $args['cap'] = (object) array_merge( $default_caps, $args['capabilities'] );
- unset( $args['capabilities'] );
- $args['name'] = $taxonomy;
- $args['object_type'] = array_unique( (array) $object_type );
- $args['labels'] = get_taxonomy_labels( (object) $args );
- $args['label'] = $args['labels']->name;
- // If not set, use the default meta box
- if ( null === $args['meta_box_cb'] ) {
- if ( $args['hierarchical'] )
- $args['meta_box_cb'] = 'post_categories_meta_box';
- else
- $args['meta_box_cb'] = 'post_tags_meta_box';
- }
- $wp_taxonomies[ $taxonomy ] = (object) $args;
- // register callback handling for metabox
- add_filter( 'wp_ajax_add-' . $taxonomy, '_wp_ajax_add_hierarchical_term' );
- /**
- * Fires after a taxonomy is registered.
- *
- * @since 3.3.0
- *
- * @param string $taxonomy Taxonomy slug.
- * @param array|string $object_type Object type or array of object types.
- * @param array $args Array of taxonomy registration arguments.
- */
- do_action( 'registered_taxonomy', $taxonomy, $object_type, $args );
- }
- /**
- * Builds an object with all taxonomy labels out of a taxonomy object
- *
- * Accepted keys of the label array in the taxonomy object:
- *
- * - name - general name for the taxonomy, usually plural. The same as and overridden by $tax->label. Default is Tags/Categories
- * - singular_name - name for one object of this taxonomy. Default is Tag/Category
- * - search_items - Default is Search Tags/Search Categories
- * - popular_items - This string isn't used on hierarchical taxonomies. Default is Popular Tags
- * - all_items - Default is All Tags/All Categories
- * - parent_item - This string isn't used on non-hierarchical taxonomies. In hierarchical ones the default is Parent Category
- * - parent_item_colon - The same as `parent_item`, but with colon `:` in the end
- * - edit_item - Default is Edit Tag/Edit Category
- * - view_item - Default is View Tag/View Category
- * - update_item - Default is Update Tag/Update Category
- * - add_new_item - Default is Add New Tag/Add New Category
- * - new_item_name - Default is New Tag Name/New Category Name
- * - separate_items_with_commas - This string isn't used on hierarchical taxonomies. Default is "Separate tags with commas", used in the meta box.
- * - 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.
- * - 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.
- * - not_found - Default is "No tags found"/"No categories found", used in the meta box and taxonomy list table.
- *
- * Above, the first default value is for non-hierarchical taxonomies (like tags) and the second one is for hierarchical taxonomies (like categories).
- *
- * @since 3.0.0
- * @param object $tax Taxonomy object
- * @return object object with all the labels as member variables
- */
- function get_taxonomy_labels( $tax ) {
- $tax->labels = (array) $tax->labels;
- if ( isset( $tax->helps ) && empty( $tax->labels['separate_items_with_commas'] ) )
- $tax->labels['separate_items_with_commas'] = $tax->helps;
- if ( isset( $tax->no_tagcloud ) && empty( $tax->labels['not_found'] ) )
- $tax->labels['not_found'] = $tax->no_tagcloud;
- $nohier_vs_hier_defaults = array(
- 'name' => array( _x( 'Tags', 'taxonomy general name' ), _x( 'Categories', 'taxonomy general name' ) ),
- 'singular_name' => array( _x( 'Tag', 'taxonomy singular name' ), _x( 'Category', 'taxonomy singular name' ) ),
- 'search_items' => array( __( 'Search Tags' ), __( 'Search Categories' ) ),
- 'popular_items' => array( __( 'Popular Tags' ), null ),
- 'all_items' => array( __( 'All Tags' ), __( 'All Categories' ) ),
- 'parent_item' => array( null, __( 'Parent Category' ) ),
- 'parent_item_colon' => array( null, __( 'Parent Category:' ) ),
- 'edit_item' => array( __( 'Edit Tag' ), __( 'Edit Category' ) ),
- 'view_item' => array( __( 'View Tag' ), __( 'View Category' ) ),
- 'update_item' => array( __( 'Update Tag' ), __( 'Update Category' ) ),
- 'add_new_item' => array( __( 'Add New Tag' ), __( 'Add New Category' ) ),
- 'new_item_name' => array( __( 'New Tag Name' ), __( 'New Category Name' ) ),
- 'separate_items_with_commas' => array( __( 'Separate tags with commas' ), null ),
- 'add_or_remove_items' => array( __( 'Add or remove tags' ), null ),
- 'choose_from_most_used' => array( __( 'Choose from the most used tags' ), null ),
- 'not_found' => array( __( 'No tags found.' ), __( 'No categories found.' ) ),
- );
- $nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name'];
- return _get_custom_object_labels( $tax, $nohier_vs_hier_defaults );
- }
- /**
- * Add an already registered taxonomy to an object type.
- *
- * @since 3.0.0
- * @uses $wp_taxonomies Modifies taxonomy object
- *
- * @param string $taxonomy Name of taxonomy object
- * @param string $object_type Name of the object type
- * @return bool True if successful, false if not
- */
- function register_taxonomy_for_object_type( $taxonomy, $object_type) {
- global $wp_taxonomies;
- if ( !isset($wp_taxonomies[$taxonomy]) )
- return false;
- if ( ! get_post_type_object($object_type) )
- return false;
- if ( ! in_array( $object_type, $wp_taxonomies[$taxonomy]->object_type ) )
- $wp_taxonomies[$taxonomy]->object_type[] = $object_type;
- return true;
- }
- /**
- * Remove an already registered taxonomy from an object type.
- *
- * @since 3.7.0
- *
- * @param string $taxonomy Name of taxonomy object.
- * @param string $object_type Name of the object type.
- * @return bool True if successful, false if not.
- */
- function unregister_taxonomy_for_object_type( $taxonomy, $object_type ) {
- global $wp_taxonomies;
- if ( ! isset( $wp_taxonomies[ $taxonomy ] ) )
- return false;
- if ( ! get_post_type_object( $object_type ) )
- return false;
- $key = array_search( $object_type, $wp_taxonomies[ $taxonomy ]->object_type, true );
- if ( false === $key )
- return false;
- unset( $wp_taxonomies[ $taxonomy ]->object_type[ $key ] );
- return true;
- }
- //
- // Term API
- //
- /**
- * Retrieve object_ids of valid taxonomy and term.
- *
- * The strings of $taxonomies must exist before this function will continue. On
- * failure of finding a valid taxonomy, it will return an WP_Error class, kind
- * of like Exceptions in PHP 5, except you can't catch them. Even so, you can
- * still test for the WP_Error class and get the error message.
- *
- * The $terms aren't checked the same as $taxonomies, but still need to exist
- * for $object_ids to be returned.
- *
- * It is possible to change the order that object_ids is returned by either
- * using PHP sort family functions or using the database by using $args with
- * either ASC or DESC array. The value should be in the key named 'order'.
- *
- * @since 2.3.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int|array $term_ids Term id or array of term ids of terms that will be used
- * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names
- * @param array|string $args Change the order of the object_ids, either ASC or DESC
- * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success
- * the array can be empty meaning that there are no $object_ids found or it will return the $object_ids found.
- */
- function get_objects_in_term( $term_ids, $taxonomies, $args = array() ) {
- global $wpdb;
- if ( ! is_array( $term_ids ) ) {
- $term_ids = array( $term_ids );
- }
- if ( ! is_array( $taxonomies ) ) {
- $taxonomies = array( $taxonomies );
- }
- foreach ( (array) $taxonomies as $taxonomy ) {
- if ( ! taxonomy_exists( $taxonomy ) ) {
- return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) );
- }
- }
- $defaults = array( 'order' => 'ASC' );
- $args = wp_parse_args( $args, $defaults );
- $order = ( 'desc' == strtolower( $args['order'] ) ) ? 'DESC' : 'ASC';
- $term_ids = array_map('intval', $term_ids );
- $taxonomies = "'" . implode( "', '", $taxonomies ) . "'";
- $term_ids = "'" . implode( "', '", $term_ids ) . "'";
- $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");
- if ( ! $object_ids ){
- return array();
- }
- return $object_ids;
- }
- /**
- * Given a taxonomy query, generates SQL to be appended to a main query.
- *
- * @since 3.1.0
- *
- * @see WP_Tax_Query
- *
- * @param array $tax_query A compact tax query
- * @param string $primary_table
- * @param string $primary_id_column
- * @return array
- */
- function get_tax_sql( $tax_query, $primary_table, $primary_id_column ) {
- $tax_query_obj = new WP_Tax_Query( $tax_query );
- return $tax_query_obj->get_sql( $primary_table, $primary_id_column );
- }
- /**
- * Class for generating SQL clauses that filter a primary query according to object taxonomy terms.
- *
- * `WP_Tax_Query` is a helper that allows primary query classes, such as {@see WP_Query}, to filter
- * their results by object metadata, by generating `JOIN` and `WHERE` subclauses to be attached
- * to the primary SQL query string.
- *
- * @since 3.1.0
- */
- class WP_Tax_Query {
- /**
- * Array of taxonomy queries.
- *
- * See {@see WP_Tax_Query::__construct()} for information on tax query arguments.
- *
- * @since 3.1.0
- * @access public
- * @var array
- */
- public $queries = array();
- /**
- * The relation between the queries. Can be one of 'AND' or 'OR'.
- *
- * @since 3.1.0
- * @access public
- * @var string
- */
- public $relation;
- /**
- * Standard response when the query should not return any rows.
- *
- * @since 3.2.0
- * @access private
- * @var string
- */
- private static $no_results = array( 'join' => array( '' ), 'where' => array( '0 = 1' ) );
- /**
- * A flat list of table aliases used in the JOIN clauses.
- *
- * @since 4.1.0
- * @access protected
- * @var array
- */
- protected $table_aliases = array();
- /**
- * Terms and taxonomies fetched by this query.
- *
- * We store this data in a flat array because they are referenced in a
- * number of places by {@see WP_Query}.
- *
- * @since 4.1.0
- * @access public
- * @var array
- */
- public $queried_terms = array();
- /**
- * Database table that where the metadata's objects are stored (eg $wpdb->users).
- *
- * @since 4.1.0
- * @access public
- * @var string
- */
- public $primary_table;
- /**
- * Column in 'primary_table' that represents the ID of the object.
- *
- * @since 4.1.0
- * @access public
- * @var string
- */
- public $primary_id_column;
- /**
- * Constructor.
- *
- * @since 3.1.0
- * @since 4.1.0 Added support for `$operator` 'NOT EXISTS' and 'EXISTS' values.
- * @access public
- *
- * @param array $tax_query {
- * Array of taxonomy query clauses.
- *
- * @type string $relation Optional. The MySQL keyword used to join
- * the clauses of the query. Accepts 'AND', or 'OR'. Default 'AND'.
- * @type array {
- * Optional. An array of first-order clause parameters, or another fully-formed tax query.
- *
- * @type string $taxonomy Taxonomy being queried. Optional when field=term_taxonomy_id.
- * @type string|int|array $terms Term or terms to filter by.
- * @type string $field Field to match $terms against. Accepts 'term_id', 'slug',
- * 'name', or 'term_taxonomy_id'. Default: 'term_id'.
- * @type string $operator MySQL operator to be used with $terms in the WHERE clause.
- * Accepts 'AND', 'IN', 'NOT IN', 'EXISTS', 'NOT EXISTS'.
- * Default: 'IN'.
- * @type bool $include_children Optional. Whether to include child terms.
- * Requires a $taxonomy. Default: true.
- * }
- * }
- */
- public function __construct( $tax_query ) {
- if ( isset( $tax_query['relation'] ) ) {
- $this->relation = $this->sanitize_relation( $tax_query['relation'] );
- } else {
- $this->relation = 'AND';
- }
- $this->queries = $this->sanitize_query( $tax_query );
- }
- /**
- * Ensure the 'tax_query' argument passed to the class constructor is well-formed.
- *
- * Ensures that each query-level clause has a 'relation' key, and that
- * each first-order clause contains all the necessary keys from `$defaults`.
- *
- * @since 4.1.0
- * @access public
- *
- * @param array $queries Array of queries clauses.
- * @return array Sanitized array of query clauses.
- */
- public function sanitize_query( $queries ) {
- $cleaned_query = array();
- $defaults = array(
- 'taxonomy' => '',
- 'terms' => array(),
- 'field' => 'term_id',
- 'operator' => 'IN',
- 'include_children' => true,
- );
- foreach ( $queries as $key => $query ) {
- if ( 'relation' === $key ) {
- $cleaned_query['relation'] = $this->sanitize_relation( $query );
- // First-order clause.
- } elseif ( self::is_first_order_clause( $query ) ) {
- $cleaned_clause = array_merge( $defaults, $query );
- $cleaned_clause['terms'] = (array) $cleaned_clause['terms'];
- $cleaned_query[] = $cleaned_clause;
- /*
- * Keep a copy of the clause in the flate
- * $queried_terms array, for use in WP_Query.
- */
- if ( ! empty( $cleaned_clause['taxonomy'] ) && 'NOT IN' !== $cleaned_clause['operator'] ) {
- $taxonomy = $cleaned_clause['taxonomy'];
- if ( ! isset( $this->queried_terms[ $taxonomy ] ) ) {
- $this->queried_terms[ $taxonomy ] = array();
- }
- /*
- * Backward compatibility: Only store the first
- * 'terms' and 'field' found for a given taxonomy.
- */
- if ( ! empty( $cleaned_clause['terms'] ) && ! isset( $this->queried_terms[ $taxonomy ]['terms'] ) ) {
- $this->queried_terms[ $taxonomy ]['terms'] = $cleaned_clause['terms'];
- }
- if ( ! empty( $cleaned_clause['field'] ) && ! isset( $this->queried_terms[ $taxonomy ]['field'] ) ) {
- $this->queried_terms[ $taxonomy ]['field'] = $cleaned_clause['field'];
- }
- }
- // Otherwise, it's a nested query, so we recurse.
- } elseif ( is_array( $query ) ) {
- $cleaned_subquery = $this->sanitize_query( $query );
- if ( ! empty( $cleaned_subquery ) ) {
- // All queries with children must have a relation.
- if ( ! isset( $cleaned_subquery['relation'] ) ) {
- $cleaned_subquery['relation'] = 'AND';
- }
- $cleaned_query[] = $cleaned_subquery;
- }
- }
- }
- return $cleaned_query;
- }
- /**
- * Sanitize a 'relation' operator.
- *
- * @since 4.1.0
- * @access public
- *
- * @param string $relation Raw relation key from the query argument.
- * @return string Sanitized relation ('AND' or 'OR').
- */
- public function sanitize_relation( $relation ) {
- if ( 'OR' === strtoupper( $relation ) ) {
- return 'OR';
- } else {
- return 'AND';
- }
- }
- /**
- * Determine whether a clause is first-order.
- *
- * A "first-order" clause is one that contains any of the first-order
- * clause keys ('terms', 'taxonomy', 'include_children', 'field',
- * 'operator'). An empty clause also counts as a first-order clause,
- * for backward compatibility. Any clause that doesn't meet this is
- * determined, by process of elimination, to be a higher-order query.
- *
- * @since 4.1.0
- * @access protected
- *
- * @param array $query Tax query arguments.
- * @return bool Whether the query clause is a first-order clause.
- */
- protected static function is_first_order_clause( $query ) {
- 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 ) );
- }
- /**
- * Generates SQL clauses to be appended to a main query.
- *
- * @since 3.1.0
- * @access public
- *
- * @param string $primary_table Database table where the object being filtered is stored (eg wp_users).
- * @param string $primary_id_column ID column for the filtered object in $primary_table.
- * @return array {
- * Array containing JOIN and WHERE SQL clauses to append to the main query.
- *
- * @type string $join SQL fragment to append to the main JOIN clause.
- * @type string $where SQL fragment to append to the main WHERE clause.
- * }
- */
- public function get_sql( $primary_table, $primary_id_column ) {
- $this->primary_table = $primary_table;
- $this->primary_id_column = $primary_id_column;
- return $this->get_sql_clauses();
- }
- /**
- * Generate SQL clauses to be appended to a main query.
- *
- * Called by the public {@see WP_Tax_Query::get_sql()}, this method
- * is abstracted out to maintain parity with the other Query classes.
- *
- * @since 4.1.0
- * @access protected
- *
- * @return array {
- * Array containing JOIN and WHERE SQL clauses to append to the main query.
- *
- * @type string $join SQL fragment to append to the main JOIN clause.
- * @type string $where SQL fragment to append to the main WHERE clause.
- * }
- */
- protected function get_sql_clauses() {
- /*
- * $queries are passed by reference to get_sql_for_query() for recursion.
- * To keep $this->queries unaltered, pass a copy.
- */
- $queries = $this->queries;
- $sql = $this->get_sql_for_query( $queries );
- if ( ! empty( $sql['where'] ) ) {
- $sql['where'] = ' AND ' . $sql['where'];
- }
- return $sql;
- }
- /**
- * Generate SQL clauses for a single query array.
- *
- * If nested subqueries are found, this method recurses the tree to
- * produce the properly nested SQL.
- *
- * @since 4.1.0
- * @access protected
- *
- * @param array $query Query to parse, passed by reference.
- * @param int $depth Optional. Number of tree levels deep we currently are.
- * Used to calculate indentation. Default 0.
- * @return array {
- * Array containing JOIN and WHERE SQL clauses to append to a single query array.
- *
- * @type string $join SQL fragment to append to the main JOIN clause.
- * @type string $where SQL fragment to append to the main WHERE clause.
- * }
- */
- protected function get_sql_for_query( &$query, $depth = 0 ) {
- $sql_chunks = array(
- 'join' => array(),
- 'where' => array(),
- );
- $sql = array(
- 'join' => '',
- 'where' => '',
- );
- $indent = '';
- for ( $i = 0; $i < $depth; $i++ ) {
- $indent .= " ";
- }
- foreach ( $query as $key => &$clause ) {
- if ( 'relation' === $key ) {
- $relation = $query['relation'];
- } elseif ( is_array( $clause ) ) {
- // This is a first-order clause.
- if ( $this->is_first_order_clause( $clause ) ) {
- $clause_sql = $this->get_sql_for_clause( $clause, $query );
- $where_count = count( $clause_sql['where'] );
- if ( ! $where_count ) {
- $sql_chunks['where'][] = '';
- } elseif ( 1 === $where_count ) {
- $sql_chunks['where'][] = $clause_sql['where'][0];
- } else {
- $sql_chunks['where'][] = '( ' . implode( ' AND ', $clause_sql['where'] ) . ' )';
- }
- $sql_chunks['join'] = array_merge( $sql_chunks['join'], $clause_sql['join'] );
- // This is a subquery, so we recurse.
- } else {
- $clause_sql = $this->get_sql_for_query( $clause, $depth + 1 );
- $sql_chunks['where'][] = $clause_sql['where'];
- $sql_chunks['join'][] = $clause_sql['join'];
- }
- }
- }
- // Filter to remove empties.
- $sql_chunks['join'] = array_filter( $sql_chunks['join'] );
- $sql_chunks['where'] = array_filter( $sql_chunks['where'] );
- if ( empty( $relation ) ) {
- $relation = 'AND';
- }
- // Filter duplicate JOIN clauses and combine into a single string.
- if ( ! empty( $sql_chunks['join'] ) ) {
- $sql['join'] = implode( ' ', array_unique( $sql_chunks['join'] ) );
- }
- // Generate a single WHERE clause with proper brackets and indentation.
- if ( ! empty( $sql_chunks['where'] ) ) {
- $sql['where'] = '( ' . "\n " . $indent . implode( ' ' . "\n " . $indent . $relation . ' ' . "\n " . $indent, $sql_chunks['where'] ) . "\n" . $indent . ')';
- }
- return $sql;
- }
- /**
- * Generate SQL JOIN and WHERE clauses for a "first-order" query clause.
- *
- * @since 4.1.0
- * @access public
- *
- * @param array $clause Query clause, passed by reference
- * @param array $parent_query Parent query array.
- * @return array {
- * Array containing JOIN and WHERE SQL clauses to append to a first-order query.
- *
- * @type string $join SQL fragment to append to the main JOIN clause.
- * @type string $where SQL fragment to append to the main WHERE clause.
- * }
- */
- public function get_sql_for_clause( &$clause, $parent_query ) {
- global $wpdb;
- $sql = array(
- 'where' => array(),
- 'join' => array(),
- );
- $join = '';
- $this->clean_query( $clause );
- if ( is_wp_error( $clause ) ) {
- return self::$no_results;
- }
- $terms = $clause['terms'];
- $operator = strtoupper( $clause['operator'] );
- if ( 'IN' == $operator ) {
- if ( empty( $terms ) ) {
- return self::$no_results;
- }
- $terms = implode( ',', $terms );
- /*
- * Before creating another table join, see if this clause has a
- * sibling with an existing join that can be shared.
- */
- $alias = $this->find_compatible_table_alias( $clause, $parent_query );
- if ( false === $alias ) {
- $i = count( $this->table_aliases );
- $alias = $i ? 'tt' . $i : $wpdb->term_relationships;
- // Store the alias as part of a flat array to build future iterators.
- $this->table_aliases[] = $alias;
- // Store the alias with this clause, so later siblings can use it.
- $clause['alias'] = $alias;
- $join .= " INNER JOIN $wpdb->term_relationships";
- $join .= $i ? " AS $alias" : '';
- $join .= " ON ($this->primary_table.$this->primary_id_column = $alias.object_id)";
- }
- $where = "$alias.term_taxonomy_id $operator ($terms)";
- } elseif ( 'NOT IN' == $operator ) {
- if ( empty( $terms ) ) {
- return $sql;
- }
- $terms = implode( ',', $terms );
- $where = "$this->primary_table.$this->primary_id_column NOT IN (
- SELECT object_id
- FROM $wpdb->term_relationships
- WHERE term_taxonomy_id IN ($terms)
- )";
- } elseif ( 'AND' == $operator ) {
- if ( empty( $terms ) ) {
- return $sql;
- }
- $num_terms = count( $terms );
- $terms = implode( ',', $terms );
- $where = "(
- SELECT COUNT(1)
- FROM $wpdb->term_relationships
- WHERE term_taxonomy_id IN ($terms)
- AND object_id = $this->primary_table.$this->primary_id_column
- ) = $num_terms";
- } elseif ( 'NOT EXISTS' === $operator || 'EXISTS' === $operator ) {
- $where = $wpdb->prepare( "$operator (
- SELECT 1
- FROM $wpdb->term_relationships
- INNER JOIN $wpdb->term_taxonomy
- ON $wpdb->term_taxonomy.term_taxonomy_id = $wpdb->term_relationships.term_taxonomy_id
- WHERE $wpdb->term_taxonomy.taxonomy = %s
- AND $wpdb->term_relationships.object_id = $this->primary_table.$this->primary_id_column
- )", $clause['taxonomy'] );
- }
- $sql['join'][] = $join;
- $sql['where'][] = $where;
- return $sql;
- }
- /**
- * Identify an existing table alias that is compatible with the current query clause.
- *
- * We avoid unnecessary table joins by allowing each clause to look for
- * an existing table alias that is compatible with the query that it
- * needs to perform.
- *
- * An existing alias is compatible if (a) it is a sibling of `$clause`
- * (ie, it's under the scope of the same relation), and (b) the combination
- * of operator and relation between the clauses allows for a shared table
- * join. In the case of {@see WP_Tax_Query}, this only applies to 'IN'
- * clauses that are connected by the relation 'OR'.
- *
- * @since 4.1.0
- * @access protected
- *
- * @param array $clause Query clause.
- * @param array $parent_query Parent query of $clause.
- * @return string|bool Table alias if found, otherwise false.
- */
- protected function find_compatible_table_alias( $clause, $parent_query ) {
- $alias = false;
- // Sanity check. Only IN queries use the JOIN syntax .
- if ( ! isset( $clause['operator'] ) || 'IN' !== $clause['operator'] ) {
- return $alias;
- }
- // Since we're only checking IN queries, we're only concerned with OR relations.
- if ( ! isset( $parent_query['relation'] ) || 'OR' !== $parent_query['relation'] ) {
- return $alias;
- }
- $compatible_operators = array( 'IN' );
- foreach ( $parent_query as $sibling ) {
- if ( ! is_array( $sibling ) || ! $this->is_first_order_clause( $sibling ) ) {
- continue;
- }
- if ( empty( $sibling['alias'] ) || empty( $sibling['operator'] ) ) {
- continue;
- }
- // The sibling must both have compatible operator to share its alias.
- if ( in_array( strtoupper( $sibling['operator'] ), $compatible_operators ) ) {
- $alias = $sibling['alias'];
- break;
- }
- }
- return $alias;
- }
- /**
- * Validates a single query.
- *
- * @since 3.2.0
- * @access private
- *
- * @param array &$query The single query.
- */
- private function clean_query( &$query ) {
- if ( empty( $query['taxonomy'] ) ) {
- if ( 'term_taxonomy_id' !== $query['field'] ) {
- $query = new WP_Error( 'Invalid taxonomy' );
- return;
- }
- // so long as there are shared terms, include_children requires that a taxonomy is set
- $query['include_children'] = false;
- } elseif ( ! taxonomy_exists( $query['taxonomy'] ) ) {
- $query = new WP_Error( 'Invalid taxonomy' );
- return;
- }
- $query['terms'] = array_unique( (array) $query['terms'] );
- if ( is_taxonomy_hierarchical( $query['taxonomy'] ) && $query['include_children'] ) {
- $this->transform_query( $query, 'term_id' );
- if ( is_wp_error( $query ) )
- return;
- $children = array();
- foreach ( $query['terms'] as $term ) {
- $children = array_merge( $children, get_term_children( $term, $query['taxonomy'] ) );
- $children[] = $term;
- }
- $query['terms'] = $children;
- }
- $this->transform_query( $query, 'term_taxonomy_id' );
- }
- /**
- * Transforms a single query, from one field to another.
- *
- * @since 3.2.0
- *
- * @param array &$query The single query.
- * @param string $resulting_field The resulting field. Accepts 'slug', 'name', 'term_taxonomy_id',
- * or 'term_id'. Default: 'term_id'.
- */
- public function transform_query( &$query, $resulting_field ) {
- global $wpdb;
- if ( empty( $query['terms'] ) )
- return;
- if ( $query['field'] == $resulting_field )
- return;
- $resulting_field = sanitize_key( $resulting_field );
- switch ( $query['field'] ) {
- case 'slug':
- case 'name':
- foreach ( $query['terms'] as &$term ) {
- /*
- * 0 is the $term_id parameter. We don't have a term ID yet, but it doesn't
- * matter because `sanitize_term_field()` ignores the $term_id param when the
- * context is 'db'.
- */
- $term = "'" . esc_sql( sanitize_term_field( $query['field'], $term, 0, $query['taxonomy'], 'db' ) ) . "'";
- }
- $terms = implode( ",", $query['terms'] );
- $terms = $wpdb->get_col( "
- SELECT $wpdb->term_taxonomy.$resulting_field
- FROM $wpdb->term_taxonomy
- INNER JOIN $wpdb->terms USING (term_id)
- WHERE taxonomy = '{$query['taxonomy']}'
- AND $wpdb->terms.{$query['field']} IN ($terms)
- " );
- break;
- case 'term_taxonomy_id':
- $terms = implode( ',', array_map( 'intval', $query['terms'] ) );
- $terms = $wpdb->get_col( "
- SELECT $resulting_field
- FROM $wpdb->term_taxonomy
- WHERE term_taxonomy_id IN ($terms)
- " );
- break;
- default:
- $terms = implode( ',', array_map( 'intval', $query['terms'] ) );
- $terms = $wpdb->get_col( "
- SELECT $resulting_field
- FROM $wpdb->term_taxonomy
- WHERE taxonomy = '{$query['taxonomy']}'
- AND term_id IN ($terms)
- " );
- }
- if ( 'AND' == $query['operator'] && count( $terms ) < count( $query['terms'] ) ) {
- $query = new WP_Error( 'Inexistent terms' );
- return;
- }
- $query['terms'] = $terms;
- $query['field'] = $resulting_field;
- }
- }
- /**
- * Get all Term data from database by Term ID.
- *
- * The usage of the get_term function is to apply filters to a term object. It
- * is possible to get a term object from the database before applying the
- * filters.
- *
- * $term ID must be part of $taxonomy, to get from the database. Failure, might
- * be able to be captured by the hooks. Failure would be the same value as $wpdb
- * returns for the get_row method.
- *
- * There are two hooks, one is specifically for each term, named 'get_term', and
- * the second is for the taxonomy name, 'term_$taxonomy'. Both hooks gets the
- * term object, and the taxonomy name as parameters. Both hooks are expected to
- * return a Term object.
- *
- * 'get_term' hook - Takes two parameters the term Object and the taxonomy name.
- * Must return term object. Used in get_term() as a catch-all filter for every
- * $term.
- *
- * 'get_$taxonomy' hook - Takes two parameters the term Object and the taxonomy
- * name. Must return term object. $taxonomy will be the taxonomy name, so for
- * example, if 'category', it would be 'get_category' as the filter name. Useful
- * for custom taxonomies or plugging into default taxonomies.
- *
- * @since 2.3.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
- *
- * @param int|object $term If integer, will get from database. If object will apply filters and return $term.
- * @param string $taxonomy Taxonomy name that $term is part of.
- * @param string $output Constant OBJECT, ARRAY_A, or ARRAY_N
- * @param string $filter Optional, default is raw or no WordPress defined filter will applied.
- * @return mixed|null|WP_Error Term Row from database. Will return null if $term is empty. If taxonomy does not
- * exist then WP_Error will be returned.
- */
- function get_term($term, $taxonomy, $output = OBJECT, $filter = 'raw') {
- global $wpdb;
- if ( empty($term) ) {
- $error = new WP_Error('invalid_term', __('Empty Term'));
- return $error;
- }
- if ( ! taxonomy_exists($taxonomy) ) {
- $error = new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
- return $error;
- }
- if ( is_object($term) && empty($term->filter) ) {
- wp_cache_add( $term->term_id, $term, $taxonomy );
- $_term = $term;
- } else {
- if ( is_object($term) )
- $term = $term->term_id;
- if ( !$term = (int) $term )
- return null;
- if ( ! $_term = wp_cache_get( $term, $taxonomy ) ) {
- $_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND t.term_id = %d LIMIT 1", $taxonomy, $term) );
- if ( ! $_term )
- return null;
- wp_cache_add( $term, $_term, $taxonomy );
- }
- }
- /**
- * Filter a term.
- *
- * @since 2.3.0
- *
- * @param int|object $_term Term object or ID.
- * @param string $taxonomy The taxonomy slug.
- */
- $_term = apply_filters( 'get_term', $_term, $taxonomy );
- /**
- * Filter a taxonomy.
- *
- * The dynamic portion of the filter name, `$taxonomy`, refers
- * to the taxonomy slug.
- *
- * @since 2.3.0
- *
- * @param int|object $_term Term object or ID.
- * @param string $taxonomy The taxonomy slug.
- */
- $_term = apply_filters( "get_$taxonomy", $_term, $taxonomy );
- $_term = sanitize_term($_term, $taxonomy, $filter);
- if ( $output == OBJECT ) {
- return $_term;
- } elseif ( $output == ARRAY_A ) {
- $__term = get_object_vars($_term);
- return $__term;
- } elseif ( $output == ARRAY_N ) {
- $__term = array_values(get_object_vars($_term));
- return $__term;
- } else {
- return $_term;
- }
- }
- /**
- * Get all Term data from database by Term field and data.
- *
- * Warning: $value is not escaped for 'name' $field. You must do it yourself, if
- * required.
- *
- * The default $field is 'id', therefore it is possible to also use null for
- * field, but not recommended that you do so.
- *
- * If $value does not exist, the return value will be false. If $taxonomy exists
- * and $field and $value combinations exist, the Term will be returned.
- *
- * @since 2.3.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
- *
- * @param string $field Either 'slug', 'name', 'id' (term_id), or 'term_taxonomy_id'
- * @param string|int $value Search for this term value
- * @param string $taxonomy Taxonomy Name
- * @param string $output Constant OBJECT, ARRAY_A, or ARRAY_N
- * @param string $filter Optional, default is raw or no WordPress defined filter will applied.
- * @return mixed Term Row from database. Will return false if $taxonomy does not exist or $term was not found.
- */
- function get_term_by($field, $value, $taxonomy, $output = OBJECT, $filter = 'raw') {
- global $wpdb;
- if ( ! taxonomy_exists($taxonomy) )
- return false;
- if ( 'slug' == $field ) {
- $field = 't.slug';
- $value = sanitize_title($value);
- if ( empty($value) )
- return false;
- } elseif ( 'name' == $field ) {
- // Assume already escaped
- $value = wp_unslash($value);
- $field = 't.name';
- } elseif ( 'term_taxonomy_id' == $field ) {
- $value = (int) $value;
- $field = 'tt.term_taxonomy_id';
- } else {
- $term = get_term( (int) $value, $taxonomy, $output, $filter );
- if ( is_wp_error( $term ) )
- $term = false;
- return $term;
- }
- $term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND $field = %s LIMIT 1", $taxonomy, $value ) );
- if ( ! $term )
- return false;
- wp_cache_add( $term->term_id, $term, $taxonomy );
- /** This filter is documented in wp-includes/taxonomy.php */
- $term = apply_filters( 'get_term', $term, $taxonomy );
- /** This filter is documented in wp-includes/taxonomy.php */
- $term = apply_filters( "get_$taxonomy", $term, $taxonomy );
- $term = sanitize_term($term, $taxonomy, $filter);
- if ( $output == OBJECT ) {
- return $term;
- } elseif ( $output == ARRAY_A ) {
- return get_object_vars($term);
- } elseif ( $output == ARRAY_N ) {
- return array_values(get_object_vars($term));
- } else {
- return $term;
- }
- }
- /**
- * Merge all term children into a single array of their IDs.
- *
- * This recursive function will merge all of the children of $term into the same
- * array of term IDs. Only useful for taxonomies which are hierarchical.
- *
- * Will return an empty array if $term does not exist in $taxonomy.
- *
- * @since 2.3.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string $term_id ID of Term to get children
- * @param string $taxonomy Taxonomy Name
- * @return array|WP_Error List of Term IDs. WP_Error returned if $taxonomy does not exist
- */
- function get_term_children( $term_id, $taxonomy ) {
- if ( ! taxonomy_exists($taxonomy) )
- return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
- $term_id = intval( $term_id );
- $terms = _get_term_hierarchy($taxonomy);
- if ( ! isset($terms[$term_id]) )
- return array();
- $children = $terms[$term_id];
- foreach ( (array) $terms[$term_id] as $child ) {
- if ( $term_id == $child ) {
- continue;
- }
- if ( isset($terms[$child]) )
- $children = array_merge($children, get_term_children($child, $taxonomy));
- }
- return $children;
- }
- /**
- * Get sanitized Term field.
- *
- * Does checks for $term, based on the $taxonomy. The function is for contextual
- * reasons and for simplicity of usage. See sanitize_term_field() for more
- * information.
- *
- * @since 2.3.0
- *
- * @param string $field Term field to fetch
- * @param int $term Term ID
- * @pa…
Large files files are truncated, but you can click here to view the full file