diff -r 3d4e9c994f10 -r a86126ab1dd4 wp/wp-includes/taxonomy.php --- a/wp/wp-includes/taxonomy.php Tue Oct 22 16:11:46 2019 +0200 +++ b/wp/wp-includes/taxonomy.php Tue Dec 15 13:49:49 2020 +0100 @@ -7,7 +7,7 @@ */ // -// Taxonomy Registration +// Taxonomy registration. // /** @@ -19,7 +19,7 @@ * * @since 2.8.0 * - * @global WP_Rewrite $wp_rewrite The WordPress rewrite class. + * @global WP_Rewrite $wp_rewrite WordPress rewrite component. */ function create_initial_taxonomies() { global $wp_rewrite; @@ -193,7 +193,7 @@ function get_taxonomies( $args = array(), $output = 'names', $operator = 'and' ) { global $wp_taxonomies; - $field = ( 'names' == $output ) ? 'name' : false; + $field = ( 'names' === $output ) ? 'name' : false; return wp_filter_object_list( $wp_taxonomies, $args, $operator, $field ); } @@ -214,16 +214,16 @@ * * @global array $wp_taxonomies The registered taxonomies. * - * @param array|string|WP_Post $object Name of the type of taxonomy object, or an object (row from posts) - * @param string $output Optional. The type of output to return in the array. Accepts either - * taxonomy 'names' or 'objects'. Default 'names'. - * @return array The names of all taxonomy of $object_type. + * @param string|string[]|WP_Post $object Name of the type of taxonomy object, or an object (row from posts) + * @param string $output Optional. The type of output to return in the array. Accepts either + * 'names' or 'objects'. Default 'names'. + * @return string[]|WP_Taxonomy[] The names or objects of all taxonomies of `$object_type`. */ function get_object_taxonomies( $object, $output = 'names' ) { global $wp_taxonomies; if ( is_object( $object ) ) { - if ( $object->post_type == 'attachment' ) { + if ( 'attachment' === $object->post_type ) { return get_attachment_taxonomies( $object, $output ); } $object = $object->post_type; @@ -234,7 +234,7 @@ $taxonomies = array(); foreach ( (array) $wp_taxonomies as $tax_name => $tax_obj ) { if ( array_intersect( $object, (array) $tax_obj->object_type ) ) { - if ( 'names' == $output ) { + if ( 'names' === $output ) { $taxonomies[] = $tax_name; } else { $taxonomies[ $tax_name ] = $tax_obj; @@ -334,6 +334,8 @@ * @since 4.7.0 Introduced `show_in_rest`, 'rest_base' and 'rest_controller_class' * arguments to register the Taxonomy in REST API. * @since 5.1.0 Introduced `meta_box_sanitize_cb` argument. + * @since 5.4.0 Added the registered taxonomy object as a return value. + * @since 5.5.0 Introduced `default_term` argument. * * @global array $wp_taxonomies Registered taxonomies. * @@ -363,7 +365,8 @@ * (default true). * @type bool $show_in_nav_menus Makes this taxonomy available for selection in navigation menus. If not * set, the default is inherited from `$public` (default true). - * @type bool $show_in_rest Whether to include the taxonomy in the REST API. + * @type bool $show_in_rest Whether to include the taxonomy in the REST API. Set this to true + * for the taxonomy to be available in the block editor. * @type string $rest_base To change the base url of REST API route. Default is $taxonomy. * @type string $rest_controller_class REST API Controller class name. Default is 'WP_REST_Terms_Controller'. * @type bool $show_tagcloud Whether to list the taxonomy in the Tag Cloud Widget controls. If not set, @@ -396,7 +399,7 @@ * @type bool $hierarchical Either hierarchical rewrite tag or not. Default false. * @type int $ep_mask Assign an endpoint mask. Default `EP_NONE`. * } - * @type string $query_var Sets the query var key for this taxonomy. Default `$taxonomy` key. If + * @type string|bool $query_var Sets the query var key for this taxonomy. Default `$taxonomy` key. If * false, a taxonomy cannot be loaded at `?{query_var}={term_slug}`. If a * string, the query `?{query_var}={term_slug}` will be valid. * @type callable $update_count_callback Works much like a hook, in that it will be called when the count is @@ -404,10 +407,17 @@ * to post types, which confirms that the objects are published before * counting them. Default _update_generic_term_count() for taxonomies * attached to other object types, such as users. + * @type string|array $default_term { + * Default term to be used for the taxonomy. + * + * @type string $name Name of default term. + * @type string $slug Slug for default term. Default empty. + * @type string $description Description for default term. Default empty. + * } * @type bool $_builtin This taxonomy is a "built-in" taxonomy. INTERNAL USE ONLY! * Default false. * } - * @return WP_Error|void WP_Error, if errors. + * @return WP_Taxonomy|WP_Error The registered taxonomy object on success, WP_Error object on failure. */ function register_taxonomy( $taxonomy, $object_type, $args = array() ) { global $wp_taxonomies; @@ -430,6 +440,28 @@ $taxonomy_object->add_hooks(); + // Add default term. + if ( ! empty( $taxonomy_object->default_term ) ) { + $term = term_exists( $taxonomy_object->default_term['name'], $taxonomy ); + if ( $term ) { + update_option( 'default_term_' . $taxonomy_object->name, $term['term_id'] ); + } else { + $term = wp_insert_term( + $taxonomy_object->default_term['name'], + $taxonomy, + array( + 'slug' => sanitize_title( $taxonomy_object->default_term['slug'] ), + 'description' => $taxonomy_object->default_term['description'], + ) + ); + + // Update `term_id` in options. + if ( ! is_wp_error( $term ) ) { + update_option( 'default_term_' . $taxonomy_object->name, $term['term_id'] ); + } + } + } + /** * Fires after a taxonomy is registered. * @@ -440,6 +472,8 @@ * @param array $args Array of taxonomy registration arguments. */ do_action( 'registered_taxonomy', $taxonomy, $object_type, (array) $taxonomy_object ); + + return $taxonomy_object; } /** @@ -472,6 +506,11 @@ $taxonomy_object->remove_rewrite_rules(); $taxonomy_object->remove_hooks(); + // Remove custom taxonomy default term option. + if ( ! empty( $taxonomy_object->default_term ) ) { + delete_option( 'default_term_' . $taxonomy_object->name ); + } + // Remove the taxonomy. unset( $wp_taxonomies[ $taxonomy ] ); @@ -563,7 +602,7 @@ 'no_terms' => array( __( 'No tags' ), __( 'No categories' ) ), 'items_list_navigation' => array( __( 'Tags list navigation' ), __( 'Categories list navigation' ) ), 'items_list' => array( __( 'Tags list' ), __( 'Categories list' ) ), - /* translators: Tab heading when selecting from the most used terms */ + /* translators: Tab heading when selecting from the most used terms. */ 'most_used' => array( _x( 'Most Used', 'tags' ), _x( 'Most Used', 'categories' ) ), 'back_to_items' => array( __( '← Back to Tags' ), __( '← Back to Categories' ) ), ); @@ -616,7 +655,7 @@ return false; } - if ( ! in_array( $object_type, $wp_taxonomies[ $taxonomy ]->object_type ) ) { + if ( ! in_array( $object_type, $wp_taxonomies[ $taxonomy ]->object_type, true ) ) { $wp_taxonomies[ $taxonomy ]->object_type[] = $object_type; } @@ -679,7 +718,7 @@ } // -// Term API +// Term API. // /** @@ -701,7 +740,7 @@ * * @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 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. @@ -725,7 +764,7 @@ $defaults = array( 'order' => 'ASC' ); $args = wp_parse_args( $args, $defaults ); - $order = ( 'desc' == strtolower( $args['order'] ) ) ? 'DESC' : 'ASC'; + $order = ( 'desc' === strtolower( $args['order'] ) ) ? 'DESC' : 'ASC'; $term_ids = array_map( 'intval', $term_ids ); @@ -800,17 +839,18 @@ * * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param. * - * @param int|WP_Term|object $term If integer, term data will be fetched from the database, or from the cache if - * available. If stdClass object (as in the results of a database query), will apply - * filters and return a `WP_Term` object corresponding to the `$term` data. If `WP_Term`, - * will return `$term`. - * @param string $taxonomy Optional. Taxonomy name that $term is part of. - * @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to - * a WP_Term object, an associative array, or a numeric array, respectively. Default OBJECT. - * @param string $filter Optional, default is raw or no WordPress defined filter will applied. - * @return array|WP_Term|WP_Error|null Object of the type specified by `$output` on success. When `$output` is 'OBJECT', - * a WP_Term instance is returned. If taxonomy does not exist, a WP_Error is - * returned. Returns null for miscellaneous failure. + * @param int|WP_Term|object $term If integer, term data will be fetched from the database, + * or from the cache if available. + * If stdClass object (as in the results of a database query), + * will apply filters and return a `WP_Term` object with the `$term` data. + * If `WP_Term`, will return `$term`. + * @param string $taxonomy Optional. Taxonomy name that `$term` is part of. + * @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which + * correspond to a WP_Term object, an associative array, or a numeric array, + * respectively. Default OBJECT. + * @param string $filter Optional. How to sanitize term fields. Default 'raw'. + * @return WP_Term|array|WP_Error|null WP_Term instance (or array) on success, depending on the `$output` value. + * WP_Error if `$taxonomy` does not exist. Null for miscellaneous failure. */ function get_term( $term, $taxonomy = '', $output = OBJECT, $filter = 'raw' ) { if ( empty( $term ) ) { @@ -876,9 +916,9 @@ // Sanitize term, according to the specified filter. $_term->filter( $filter ); - if ( $output == ARRAY_A ) { + if ( ARRAY_A === $output ) { return $_term->to_array(); - } elseif ( $output == ARRAY_N ) { + } elseif ( ARRAY_N === $output ) { return array_values( $_term->to_array() ); } @@ -909,17 +949,19 @@ * @since 2.3.0 * @since 4.4.0 `$taxonomy` is optional if `$field` is 'term_taxonomy_id'. Converted to return * a WP_Term object if `$output` is `OBJECT`. + * @since 5.5.0 Added 'ID' as an alias of 'id' for the `$field` parameter. * * @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 $field Either 'slug', 'name', 'id' or 'ID' (term_id), or 'term_taxonomy_id'. + * @param string|int $value Search for this term value. * @param string $taxonomy Taxonomy name. Optional, if `$field` is 'term_taxonomy_id'. - * @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to - * a WP_Term object, an associative array, or a numeric array, respectively. Default OBJECT. - * @param string $filter Optional, default is raw or no WordPress defined filter will applied. - * @return WP_Term|array|false WP_Term instance (or array) on success. Will return false if `$taxonomy` does not exist - * or `$term` was not found. + * @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which + * correspond to a WP_Term object, an associative array, or a numeric array, + * respectively. Default OBJECT. + * @param string $filter Optional. How to sanitize term fields. Default 'raw'. + * @return WP_Term|array|false WP_Term instance (or array) on success, depending on the `$output` value. + * False if `$taxonomy` does not exist or `$term` was not found. */ function get_term_by( $field, $value, $taxonomy = '', $output = OBJECT, $filter = 'raw' ) { @@ -937,7 +979,7 @@ } } - if ( 'id' === $field || 'term_id' === $field ) { + if ( 'id' === $field || 'ID' === $field || 'term_id' === $field ) { $term = get_term( (int) $value, $taxonomy, $output, $filter ); if ( is_wp_error( $term ) || null === $term ) { $term = false; @@ -976,7 +1018,7 @@ $term = array_shift( $terms ); - // In the case of 'term_taxonomy_id', override the provided `$taxonomy` with whatever we find in the db. + // In the case of 'term_taxonomy_id', override the provided `$taxonomy` with whatever we find in the DB. if ( 'term_taxonomy_id' === $field ) { $taxonomy = $term->taxonomy; } @@ -1014,7 +1056,7 @@ $children = $terms[ $term_id ]; foreach ( (array) $terms[ $term_id ] as $child ) { - if ( $term_id == $child ) { + if ( $term_id === $child ) { continue; } @@ -1039,7 +1081,8 @@ * @param string $field Term field to fetch. * @param int|WP_Term $term Term ID or object. * @param string $taxonomy Optional. Taxonomy Name. Default empty. - * @param string $context Optional, default is display. Look at sanitize_term_field() for available options. + * @param string $context Optional. How to sanitize term fields. Look at sanitize_term_field() for available options. + * Default 'display'. * @return string|int|null|WP_Error Will return an empty string if $term is not an object or if $field is not set in $term. */ function get_term_field( $field, $term, $taxonomy = '', $context = 'display' ) { @@ -1126,13 +1169,13 @@ * * @internal The `$deprecated` parameter is parsed for backward compatibility only. * - * @param string|array $args Optional. Array or string of arguments. See WP_Term_Query::__construct() + * @param array|string $args Optional. Array or string of arguments. See WP_Term_Query::__construct() * for information on accepted arguments. Default empty. - * @param array $deprecated Argument array, when using the legacy function parameter format. If present, this - * parameter will be interpreted as `$args`, and the first function parameter will - * be parsed as a taxonomy or array of taxonomies. - * @return array|int|WP_Error List of WP_Term instances and their children. Will return WP_Error, if any of $taxonomies - * do not exist. + * @param array|string $deprecated Argument array, when using the legacy function parameter format. If present, + * this parameter will be interpreted as `$args`, and the first function parameter + * will be parsed as a taxonomy or array of taxonomies. + * @return WP_Term[]|int|WP_Error Array of WP_Term instances, a count thereof, + * or WP_Error if any of the taxonomies do not exist. */ function get_terms( $args = array(), $deprecated = '' ) { $term_query = new WP_Term_Query(); @@ -1207,11 +1250,11 @@ * * @param int $term_id Term ID. * @param string $meta_key Metadata name. - * @param mixed $meta_value Metadata value. - * @param bool $unique Optional. Whether to bail if an entry with the same key is found for the term. + * @param mixed $meta_value Metadata value. Must be serializable if non-scalar. + * @param bool $unique Optional. Whether the same key should not be added. * Default false. - * @return int|WP_Error|bool Meta ID on success. WP_Error when term_id is ambiguous between taxonomies. - * False on failure. + * @return int|false|WP_Error Meta ID on success, false on failure. + * WP_Error when term_id is ambiguous between taxonomies. */ function add_term_meta( $term_id, $meta_key, $meta_value, $unique = false ) { if ( wp_term_is_shared( $term_id ) ) { @@ -1228,7 +1271,9 @@ * * @param int $term_id Term ID. * @param string $meta_key Metadata name. - * @param mixed $meta_value Optional. Metadata value. If provided, rows will only be removed that match the value. + * @param mixed $meta_value Optional. Metadata value. If provided, + * rows will only be removed that match the value. + * Must be serializable if non-scalar. Default empty. * @return bool True on success, false on failure. */ function delete_term_meta( $term_id, $meta_key, $meta_value = '' ) { @@ -1241,10 +1286,13 @@ * @since 4.4.0 * * @param int $term_id Term ID. - * @param string $key Optional. The meta key to retrieve. If no key is provided, fetches all metadata for the term. - * @param bool $single Whether to return a single value. If false, an array of all values matching the - * `$term_id`/`$key` pair will be returned. Default: false. - * @return mixed If `$single` is false, an array of metadata values. If `$single` is true, a single metadata value. + * @param string $key Optional. The meta key to retrieve. By default, + * returns data for all keys. Default empty. + * @param bool $single Optional. Whether to return a single value. + * This parameter has no effect if $key is not specified. + * Default false. + * @return mixed An array if $single is false. The value of the meta field + * if $single is true. False for an invalid $term_id. */ function get_term_meta( $term_id, $key = '', $single = false ) { return get_metadata( 'term', $term_id, $key, $single ); @@ -1261,10 +1309,14 @@ * * @param int $term_id Term ID. * @param string $meta_key Metadata key. - * @param mixed $meta_value Metadata value. - * @param mixed $prev_value Optional. Previous value to check before removing. - * @return int|WP_Error|bool Meta ID if the key didn't previously exist. True on successful update. - * WP_Error when term_id is ambiguous between taxonomies. False on failure. + * @param mixed $meta_value Metadata value. Must be serializable if non-scalar. + * @param mixed $prev_value Optional. Previous value to check before updating. + * If specified, only update existing metadata entries with + * this value. Otherwise, update all entries. Default empty. + * @return int|bool|WP_Error Meta ID if the key didn't exist. true on successful update, + * false on failure or if the value passed to the function + * is the same as the one that is already in the database. + * WP_Error when term_id is ambiguous between taxonomies. */ function update_term_meta( $term_id, $meta_key, $meta_value, $prev_value = '' ) { if ( wp_term_is_shared( $term_id ) ) { @@ -1283,7 +1335,7 @@ * @since 4.4.0 * * @param array $term_ids List of term IDs. - * @return array|false Returns false if there is nothing to update. Returns an array of metadata on success. + * @return array|false An array of metadata on success, false if there is nothing to update. */ function update_termmeta_cache( $term_ids ) { return update_meta_cache( 'term', $term_ids ); @@ -1344,7 +1396,7 @@ } /** - * Determines whether a term exists. + * Determines whether a taxonomy term exists. * * Formerly is_term(), introduced in 2.3.0. * @@ -1357,12 +1409,12 @@ * @global wpdb $wpdb WordPress database abstraction object. * * @param int|string $term The term to check. Accepts term ID, slug, or name. - * @param string $taxonomy The taxonomy name to use + * @param string $taxonomy Optional. The taxonomy name to use. * @param int $parent Optional. ID of parent term under which to confine the exists search. - * @return mixed Returns null if the term does not exist. Returns the term ID - * if no taxonomy is specified and the term ID exists. Returns - * an array of the term ID and the term taxonomy ID if the taxonomy - * is specified and the pairing exists. + * @return mixed Returns null if the term does not exist. + * Returns the term ID if no taxonomy is specified and the term ID exists. + * Returns an array of the term ID and the term taxonomy ID if the taxonomy is specified and the pairing exists. + * Returns 0 if term ID 0 is passed to the function. */ function term_exists( $term, $taxonomy = '', $parent = null ) { global $wpdb; @@ -1371,11 +1423,12 @@ $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 "; if ( is_int( $term ) ) { - if ( 0 == $term ) { + if ( 0 === $term ) { return 0; } $where = 't.term_id = %d'; if ( ! empty( $taxonomy ) ) { + // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber return $wpdb->get_row( $wpdb->prepare( $tax_select . $where . ' AND tt.taxonomy = %s', $term, $taxonomy ), ARRAY_A ); } else { return $wpdb->get_var( $wpdb->prepare( $select . $where, $term ) ); @@ -1403,24 +1456,28 @@ $where_fields[] = $taxonomy; $else_where_fields[] = $taxonomy; - if ( $result = $wpdb->get_row( $wpdb->prepare( "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 $where AND tt.taxonomy = %s $orderby $limit", $where_fields ), ARRAY_A ) ) { + $result = $wpdb->get_row( $wpdb->prepare( "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 $where AND tt.taxonomy = %s $orderby $limit", $where_fields ), ARRAY_A ); + if ( $result ) { return $result; } return $wpdb->get_row( $wpdb->prepare( "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 $else_where AND tt.taxonomy = %s $orderby $limit", $else_where_fields ), ARRAY_A ); } - if ( $result = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms as t WHERE $where $orderby $limit", $where_fields ) ) ) { + // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare + $result = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms as t WHERE $where $orderby $limit", $where_fields ) ); + if ( $result ) { return $result; } + // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare return $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms as t WHERE $else_where $orderby $limit", $else_where_fields ) ); } /** * Check if a term is an ancestor of another term. * - * You can use either an id or the term object for both parameters. + * You can use either an ID or the term object for both parameters. * * @since 3.4.0 * @@ -1440,7 +1497,7 @@ if ( empty( $term1->term_id ) || empty( $term2->parent ) ) { return false; } - if ( $term2->parent == $term1->term_id ) { + if ( $term2->parent === $term1->term_id ) { return true; } @@ -1517,18 +1574,20 @@ */ function sanitize_term_field( $field, $value, $term_id, $taxonomy, $context ) { $int_fields = array( 'parent', 'term_id', 'count', 'term_group', 'term_taxonomy_id', 'object_id' ); - if ( in_array( $field, $int_fields ) ) { + if ( in_array( $field, $int_fields, true ) ) { $value = (int) $value; if ( $value < 0 ) { $value = 0; } } - if ( 'raw' == $context ) { + $context = strtolower( $context ); + + if ( 'raw' === $context ) { return $value; } - if ( 'edit' == $context ) { + if ( 'edit' === $context ) { /** * Filters a term field to edit before it is sanitized. @@ -1556,12 +1615,12 @@ */ $value = apply_filters( "edit_{$taxonomy}_{$field}", $value, $term_id ); - if ( 'description' == $field ) { + if ( 'description' === $field ) { $value = esc_html( $value ); // textarea_escaped } else { $value = esc_attr( $value ); } - } elseif ( 'db' == $context ) { + } elseif ( 'db' === $context ) { /** * Filters a term field value before it is sanitized. @@ -1587,8 +1646,8 @@ */ $value = apply_filters( "pre_{$taxonomy}_{$field}", $value ); - // Back compat filters - if ( 'slug' == $field ) { + // Back compat filters. + if ( 'slug' === $field ) { /** * Filters the category nicename before it is sanitized. * @@ -1600,7 +1659,7 @@ */ $value = apply_filters( 'pre_category_nicename', $value ); } - } elseif ( 'rss' == $context ) { + } elseif ( 'rss' === $context ) { /** * Filters the term field for use in RSS. @@ -1657,9 +1716,9 @@ $value = apply_filters( "{$taxonomy}_{$field}", $value, $term_id, $context ); } - if ( 'attribute' == $context ) { + if ( 'attribute' === $context ) { $value = esc_attr( $value ); - } elseif ( 'js' == $context ) { + } elseif ( 'js' === $context ) { $value = esc_js( $value ); } return $value; @@ -1678,10 +1737,13 @@ * @return array|int|WP_Error Number of terms in that taxonomy or WP_Error if the taxonomy does not exist. */ function wp_count_terms( $taxonomy, $args = array() ) { - $defaults = array( 'hide_empty' => false ); + $defaults = array( + 'taxonomy' => $taxonomy, + 'hide_empty' => false, + ); $args = wp_parse_args( $args, $defaults ); - // backward compatibility + // Backward compatibility. if ( isset( $args['ignore_empty'] ) ) { $args['hide_empty'] = $args['ignore_empty']; unset( $args['ignore_empty'] ); @@ -1689,7 +1751,7 @@ $args['fields'] = 'count'; - return get_terms( $taxonomy, $args ); + return get_terms( $args ); } /** @@ -1750,7 +1812,8 @@ $term = (int) $term; - if ( ! $ids = term_exists( $term, $taxonomy ) ) { + $ids = term_exists( $term, $taxonomy ); + if ( ! $ids ) { return false; } if ( is_wp_error( $ids ) ) { @@ -1761,10 +1824,19 @@ $defaults = array(); - if ( 'category' == $taxonomy ) { - $defaults['default'] = get_option( 'default_category' ); - if ( $defaults['default'] == $term ) { - return 0; // Don't delete the default category + if ( 'category' === $taxonomy ) { + $defaults['default'] = (int) get_option( 'default_category' ); + if ( $defaults['default'] === $term ) { + return 0; // Don't delete the default category. + } + } + + // Don't delete the default custom taxonomy term. + $taxonomy_object = get_taxonomy( $taxonomy ); + if ( ! empty( $taxonomy_object->default_term ) ) { + $defaults['default'] = (int) get_option( 'default_term_' . $taxonomy ); + if ( $defaults['default'] === $term ) { + return 0; } } @@ -1791,7 +1863,7 @@ */ do_action( 'pre_delete_term', $term, $taxonomy ); - // Update children to point to new parent + // Update children to point to new parent. if ( is_taxonomy_hierarchical( $taxonomy ) ) { $term_obj = get_term( $term, $taxonomy ); if ( is_wp_error( $term_obj ) ) { @@ -1841,7 +1913,7 @@ 'orderby' => 'none', ) ); - if ( 1 == count( $terms ) && isset( $default ) ) { + if ( 1 === count( $terms ) && isset( $default ) ) { $terms = array( $default ); } else { $terms = array_diff( $terms, array( $term ) ); @@ -1872,6 +1944,7 @@ * @param int $tt_id Term taxonomy ID. */ do_action( 'delete_term_taxonomy', $tt_id ); + $wpdb->delete( $wpdb->term_taxonomy, array( 'term_taxonomy_id' => $tt_id ) ); /** @@ -1948,11 +2021,11 @@ * 'all_with_object_id', an array of `WP_Term` objects will be returned. * @since 4.7.0 Refactored to use WP_Term_Query, and to support any WP_Term_Query arguments. * - * @param int|array $object_ids The ID(s) of the object(s) to retrieve. - * @param string|array $taxonomies The taxonomies to retrieve terms from. - * @param array|string $args See WP_Term_Query::__construct() for supported arguments. + * @param int|int[] $object_ids The ID(s) of the object(s) to retrieve. + * @param string|string[] $taxonomies The taxonomy names to retrieve terms from. + * @param array|string $args See WP_Term_Query::__construct() for supported arguments. * @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. + * WP_Error if any of the taxonomies don't exist. */ function wp_get_object_terms( $object_ids, $taxonomies, $args = array() ) { if ( empty( $object_ids ) || empty( $taxonomies ) ) { @@ -1981,10 +2054,10 @@ * * @since 4.9.0 * - * @param array $args An array of arguments for retrieving terms for the given object(s). - * See {@see wp_get_object_terms()} for details. - * @param int|array $object_ids Object ID or array of IDs. - * @param string|array $taxonomies The taxonomies to retrieve terms from. + * @param array $args An array of arguments for retrieving terms for the given object(s). + * See {@see wp_get_object_terms()} for details. + * @param int[] $object_ids Array of object IDs. + * @param string[] $taxonomies Array of taxonomy names to retrieve terms from. */ $args = apply_filters( 'wp_get_object_terms_args', $args, $object_ids, $taxonomies ); @@ -1996,7 +2069,7 @@ if ( count( $taxonomies ) > 1 ) { foreach ( $taxonomies as $index => $taxonomy ) { $t = get_taxonomy( $taxonomy ); - if ( isset( $t->args ) && is_array( $t->args ) && $args != array_merge( $args, $t->args ) ) { + if ( isset( $t->args ) && is_array( $t->args ) && array_merge( $args, $t->args ) != $args ) { unset( $taxonomies[ $index ] ); $terms = array_merge( $terms, wp_get_object_terms( $object_ids, $taxonomy, array_merge( $args, $t->args ) ) ); } @@ -2028,11 +2101,11 @@ * * @since 4.2.0 * - * @param array $terms An array of terms for the given object or objects. - * @param array $object_ids Array of object IDs for which `$terms` were retrieved. - * @param array $taxonomies Array of taxonomies from which `$terms` were retrieved. - * @param array $args An array of arguments for retrieving terms for the given - * object(s). See wp_get_object_terms() for details. + * @param array $terms Array of terms for the given object or objects. + * @param int[] $object_ids Array of object IDs for which terms were retrieved. + * @param string[] $taxonomies Array of taxonomy names from which terms were retrieved. + * @param array $args Array of arguments for retrieving terms for the given + * object(s). See wp_get_object_terms() for details. */ $terms = apply_filters( 'get_object_terms', $terms, $object_ids, $taxonomies, $args ); @@ -2047,11 +2120,11 @@ * * @since 2.8.0 * - * @param array $terms An array of terms for the given object or objects. - * @param int|array $object_ids Object ID or array of IDs. - * @param string $taxonomies SQL-formatted (comma-separated and quoted) list of taxonomy names. - * @param array $args An array of arguments for retrieving terms for the given object(s). - * See wp_get_object_terms() for details. + * @param array $terms Array of terms for the given object or objects. + * @param int[] $object_ids Array of object IDs for which terms were retrieved. + * @param string[] $taxonomies Array of taxonomy names from which terms were retrieved. + * @param array $args Array of arguments for retrieving terms for the given + * object(s). See wp_get_object_terms() for details. */ return apply_filters( 'wp_get_object_terms', $terms, $object_ids, $taxonomies, $args ); } @@ -2065,7 +2138,7 @@ * 3. The 'term_id_filter' is evaluated. * 4. The term cache is cleaned. * 5. Several more actions are fired. - * 6. An array is returned containing the term_id and term_taxonomy_id. + * 6. An array is returned containing the `term_id` and `term_taxonomy_id`. * * If the 'slug' argument is not empty, then it is checked to see if the term * is invalid. If it is not a valid, existing term, it is added and the term_id @@ -2075,7 +2148,7 @@ * the term is inserted and the term_id will be given. * * Error handling: - * If $taxonomy does not exist or $term is empty, + * If `$taxonomy` does not exist or `$term` is empty, * a WP_Error object will be returned. * * If the term already exists on the same hierarchical level, @@ -2085,7 +2158,7 @@ * * @since 2.3.0 * - * @param string $term The term to add or update. + * @param string $term The term name to add. * @param string $taxonomy The taxonomy to which to add the term. * @param array|string $args { * Optional. Array or string of arguments for inserting a term. @@ -2105,24 +2178,29 @@ if ( ! taxonomy_exists( $taxonomy ) ) { return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) ); } + /** * Filters a term before it is sanitized and inserted into the database. * * @since 3.0.0 * - * @param string $term The term to add or update. - * @param string $taxonomy Taxonomy slug. + * @param string|WP_Error $term The term name to add, or a WP_Error object if there's an error. + * @param string $taxonomy Taxonomy slug. */ $term = apply_filters( 'pre_insert_term', $term, $taxonomy ); + if ( is_wp_error( $term ) ) { return $term; } - if ( is_int( $term ) && 0 == $term ) { + + if ( is_int( $term ) && 0 === $term ) { return new WP_Error( 'invalid_term_id', __( 'Invalid term ID.' ) ); } - if ( '' == trim( $term ) ) { + + if ( '' === trim( $term ) ) { return new WP_Error( 'empty_term_name', __( 'A name is required for this term.' ) ); } + $defaults = array( 'alias_of' => '', 'description' => '', @@ -2183,8 +2261,8 @@ * unless a unique slug has been explicitly provided. */ $name_matches = get_terms( - $taxonomy, array( + 'taxonomy' => $taxonomy, 'name' => $name, 'hide_empty' => false, 'parent' => $args['parent'], @@ -2211,8 +2289,8 @@ if ( ! $slug_provided || $name_match->slug === $slug || $slug_match ) { if ( is_taxonomy_hierarchical( $taxonomy ) ) { $siblings = get_terms( - $taxonomy, array( + 'taxonomy' => $taxonomy, 'get' => 'all', 'parent' => $parent, 'update_term_meta_cache' => false, @@ -2220,9 +2298,12 @@ ); $existing_term = null; - if ( ( ! $slug_provided || $name_match->slug === $slug ) && in_array( $name, wp_list_pluck( $siblings, 'name' ) ) ) { + $sibling_names = wp_list_pluck( $siblings, 'name' ); + $sibling_slugs = wp_list_pluck( $siblings, 'slug' ); + + if ( ( ! $slug_provided || $name_match->slug === $slug ) && in_array( $name, $sibling_names, true ) ) { $existing_term = $name_match; - } elseif ( $slug_match && in_array( $slug, wp_list_pluck( $siblings, 'slug' ) ) ) { + } elseif ( $slug_match && in_array( $slug, $sibling_slugs, true ) ) { $existing_term = $slug_match; } @@ -2256,7 +2337,7 @@ $term_id = (int) $wpdb->insert_id; - // Seems unreachable, However, Is used in the case that a term name is provided, which sanitizes to an empty string. + // Seems unreachable. However, is used in the case that a term name is provided, which sanitizes to an empty string. if ( empty( $slug ) ) { $slug = sanitize_title( $slug, $term_id ); @@ -2276,7 +2357,11 @@ 'term_taxonomy_id' => $tt_id, ); } - $wpdb->insert( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent' ) + array( 'count' => 0 ) ); + + if ( false === $wpdb->insert( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent' ) + array( 'count' => 0 ) ) ) { + return new WP_Error( 'db_insert_error', __( 'Could not insert term taxonomy into the database.' ), $wpdb->last_error ); + } + $tt_id = (int) $wpdb->insert_id; /* @@ -2349,7 +2434,7 @@ * @since 2.3.0 * * @param int $term_id Term ID. - * @param int $tt_id Taxonomy term ID. + * @param int $tt_id Term taxonomy ID. */ $term_id = apply_filters( 'term_id_filter', $term_id, $tt_id ); @@ -2379,6 +2464,32 @@ */ do_action( "created_{$taxonomy}", $term_id, $tt_id ); + /** + * Fires after a term has been saved, and the term cache has been cleared. + * + * @since 5.5.0 + * + * @param int $term_id Term ID. + * @param int $tt_id Term taxonomy ID. + * @param string $taxonomy Taxonomy slug. + * @param bool $update Whether this is an existing term being updated. + */ + do_action( 'saved_term', $term_id, $tt_id, $taxonomy, false ); + + /** + * Fires after a term in a specific taxonomy has been saved, and the term + * cache has been cleared. + * + * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug. + * + * @since 5.5.0 + * + * @param int $term_id Term ID. + * @param int $tt_id Term taxonomy ID. + * @param bool $update Whether this is an existing term being updated. + */ + do_action( "saved_{$taxonomy}", $term_id, $tt_id, false ); + return array( 'term_id' => $term_id, 'term_taxonomy_id' => $tt_id, @@ -2398,15 +2509,15 @@ * * @since 2.3.0 * - * @global wpdb $wpdb The WordPress database abstraction object. + * @global wpdb $wpdb WordPress database abstraction object. * * @param int $object_id The object to relate to. - * @param string|int|array $terms A single term slug, single term id, or array of either term slugs or ids. + * @param string|int|array $terms A single term slug, single term ID, or array of either term slugs or IDs. * Will replace all existing related terms in this taxonomy. Passing an * empty value will remove all related terms. * @param string $taxonomy The context in which to relate the term to the object. * @param bool $append Optional. If false will delete difference of terms. Default false. - * @return array|WP_Error Term taxonomy IDs of the affected terms. + * @return array|WP_Error Term taxonomy IDs of the affected terms or WP_Error on failure. */ function wp_set_object_terms( $object_id, $terms, $taxonomy, $append = false ) { global $wpdb; @@ -2440,20 +2551,25 @@ $new_tt_ids = array(); foreach ( (array) $terms as $term ) { - if ( ! strlen( trim( $term ) ) ) { + if ( '' === trim( $term ) ) { continue; } - if ( ! $term_info = term_exists( $term, $taxonomy ) ) { + $term_info = term_exists( $term, $taxonomy ); + + if ( ! $term_info ) { // Skip if a non-existent term ID is passed. if ( is_int( $term ) ) { continue; } + $term_info = wp_insert_term( $term, $taxonomy ); } + if ( is_wp_error( $term_info ) ) { return $term_info; } + $term_ids[] = $term_info['term_id']; $tt_id = $term_info['term_taxonomy_id']; $tt_ids[] = $tt_id; @@ -2473,6 +2589,7 @@ * @param string $taxonomy Taxonomy slug. */ do_action( 'add_term_relationship', $object_id, $tt_id, $taxonomy ); + $wpdb->insert( $wpdb->term_relationships, array( @@ -2492,6 +2609,7 @@ * @param string $taxonomy Taxonomy slug. */ do_action( 'added_term_relationship', $object_id, $tt_id, $taxonomy ); + $new_tt_ids[] = $tt_id; } @@ -2515,9 +2633,11 @@ } $t = get_taxonomy( $taxonomy ); + if ( ! $append && isset( $t->sort ) && $t->sort ) { - $values = array(); - $term_order = 0; + $values = array(); + $term_order = 0; + $final_tt_ids = wp_get_object_terms( $object_id, $taxonomy, @@ -2526,11 +2646,13 @@ 'update_term_meta_cache' => false, ) ); + foreach ( $tt_ids as $tt_id ) { - if ( in_array( $tt_id, $final_tt_ids ) ) { + if ( in_array( (int) $tt_id, $final_tt_ids, true ) ) { $values[] = $wpdb->prepare( '(%d, %d, %d)', $object_id, $tt_id, ++$term_order ); } } + if ( $values ) { if ( false === $wpdb->query( "INSERT INTO $wpdb->term_relationships (object_id, term_taxonomy_id, term_order) VALUES " . join( ',', $values ) . ' ON DUPLICATE KEY UPDATE term_order = VALUES(term_order)' ) ) { return new WP_Error( 'db_insert_error', __( 'Could not insert term relationship into the database.' ), $wpdb->last_error ); @@ -2554,6 +2676,7 @@ * @param array $old_tt_ids Old array of term taxonomy IDs. */ do_action( 'set_object_terms', $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids ); + return $tt_ids; } @@ -2599,11 +2722,12 @@ $tt_ids = array(); foreach ( (array) $terms as $term ) { - if ( ! strlen( trim( $term ) ) ) { + if ( '' === trim( $term ) ) { continue; } - if ( ! $term_info = term_exists( $term, $taxonomy ) ) { + $term_info = term_exists( $term, $taxonomy ); + if ( ! $term_info ) { // Skip if a non-existent term ID is passed. if ( is_int( $term ) ) { continue; @@ -2631,6 +2755,7 @@ * @param string $taxonomy Taxonomy slug. */ do_action( 'delete_term_relationships', $object_id, $tt_ids, $taxonomy ); + $deleted = $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN ($in_tt_ids)", $object_id ) ); wp_cache_delete( $object_id, $taxonomy . '_relationships' ); @@ -2728,22 +2853,22 @@ if ( apply_filters( 'wp_unique_term_slug_is_bad_slug', $needs_suffix, $slug, $term ) ) { if ( $parent_suffix ) { $slug .= $parent_suffix; + } + + if ( ! empty( $term->term_id ) ) { + $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s AND term_id != %d", $slug, $term->term_id ); } else { - if ( ! empty( $term->term_id ) ) { - $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s AND term_id != %d", $slug, $term->term_id ); - } else { - $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $slug ); - } - - if ( $wpdb->get_var( $query ) ) { - $num = 2; - do { - $alt_slug = $slug . "-$num"; - $num++; - $slug_check = $wpdb->get_var( $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $alt_slug ) ); - } while ( $slug_check ); - $slug = $alt_slug; - } + $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $slug ); + } + + if ( $wpdb->get_var( $query ) ) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + $num = 2; + do { + $alt_slug = $slug . "-$num"; + $num++; + $slug_check = $wpdb->get_var( $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $alt_slug ) ); + } while ( $slug_check ); + $slug = $alt_slug; } } @@ -2762,32 +2887,37 @@ /** * Update term based on arguments provided. * - * The $args will indiscriminately override all values with the same field name. + * The `$args` will indiscriminately override all values with the same field name. * Care must be taken to not override important information need to update or * update will fail (or perhaps create a new term, neither would be acceptable). * * Defaults will set 'alias_of', 'description', 'parent', and 'slug' if not - * defined in $args already. - * - * 'alias_of' will create a term group, if it doesn't already exist, and update - * it for the $term. - * - * If the 'slug' argument in $args is missing, then the 'name' in $args will be - * used. It should also be noted that if you set 'slug' and it isn't unique then - * a WP_Error will be passed back. If you don't pass any slug, then a unique one - * will be created for you. - * - * For what can be overrode in `$args`, check the term scheme can contain and stay - * away from the term keys. + * defined in `$args` already. + * + * 'alias_of' will create a term group, if it doesn't already exist, and + * update it for the `$term`. + * + * If the 'slug' argument in `$args` is missing, then the 'name' will be used. + * If you set 'slug' and it isn't unique, then a WP_Error is returned. + * If you don't pass any slug, then a unique one will be created. * * @since 2.3.0 * * @global wpdb $wpdb WordPress database abstraction object. * - * @param int $term_id The ID of the term - * @param string $taxonomy The context in which to relate the term to the object. - * @param array|string $args Optional. Array of get_terms() arguments. Default empty array. - * @return array|WP_Error Returns Term ID and Taxonomy Term ID + * @param int $term_id The ID of the term. + * @param string $taxonomy The taxonomy of the term. + * @param array|string $args { + * Optional. Array or string of arguments for updating a term. + * + * @type string $alias_of Slug of the term to make this term an alias of. + * Default empty string. Accepts a term slug. + * @type string $description The term description. Default empty string. + * @type int $parent The id of the parent term. Default 0. + * @type string $slug The term slug to use. Default empty string. + * } + * @return array|WP_Error An array containing the `term_id` and `term_taxonomy_id`, + * WP_Error otherwise. */ function wp_update_term( $term_id, $taxonomy, $args = array() ) { global $wpdb; @@ -2798,7 +2928,7 @@ $term_id = (int) $term_id; - // First, get all of the original args + // First, get all of the original args. $term = get_term( $term_id, $taxonomy ); if ( is_wp_error( $term ) ) { @@ -2834,7 +2964,7 @@ $parsed_args['name'] = $name; $parsed_args['description'] = $description; - if ( '' == trim( $name ) ) { + if ( '' === trim( $name ) ) { return new WP_Error( 'empty_term_name', __( 'A name is required for this term.' ) ); } @@ -2890,17 +3020,17 @@ * @param array $parsed_args An array of potentially altered update arguments for the given term. * @param array $args An array of update arguments for the given term. */ - $parent = apply_filters( 'wp_update_term_parent', $args['parent'], $term_id, $taxonomy, $parsed_args, $args ); - - // Check for duplicate slug + $parent = (int) apply_filters( 'wp_update_term_parent', $args['parent'], $term_id, $taxonomy, $parsed_args, $args ); + + // Check for duplicate slug. $duplicate = get_term_by( 'slug', $slug, $taxonomy ); - if ( $duplicate && $duplicate->term_id != $term_id ) { + if ( $duplicate && $duplicate->term_id !== $term_id ) { // If an empty slug was passed or the parent changed, reset the slug to something unique. // Otherwise, bail. - if ( $empty_slug || ( $parent != $term['parent'] ) ) { + if ( $empty_slug || ( $parent !== (int) $term['parent'] ) ) { $slug = wp_unique_term_slug( $slug, (object) $args ); } else { - /* translators: %s: taxonomy term slug */ + /* translators: %s: Taxonomy term slug. */ return new WP_Error( 'duplicate_term_slug', sprintf( __( 'The slug “%s” is already in use by another term.' ), $slug ) ); } } @@ -2938,6 +3068,7 @@ $data = apply_filters( 'wp_update_term_data', $data, $term_id, $taxonomy, $args ); $wpdb->update( $wpdb->terms, $data, compact( 'term_id' ) ); + if ( empty( $slug ) ) { $slug = sanitize_title( $name, $term_id ); $wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) ); @@ -3028,6 +3159,12 @@ */ do_action( "edited_{$taxonomy}", $term_id, $tt_id ); + /** This action is documented in wp-includes/taxonomy.php */ + do_action( 'saved_term', $term_id, $tt_id, $taxonomy, true ); + + /** This action is documented in wp-includes/taxonomy.php */ + do_action( "saved_{$taxonomy}", $term_id, $tt_id, true ); + return array( 'term_id' => $term_id, 'term_taxonomy_id' => $tt_id, @@ -3039,8 +3176,6 @@ * * @since 2.5.0 * - * @staticvar bool $_defer - * * @param bool $defer Optional. Enable if true, disable if false. * @return bool Whether term counting is enabled or disabled. */ @@ -3049,7 +3184,7 @@ if ( is_bool( $defer ) ) { $_defer = $defer; - // flush any deferred counts + // Flush any deferred counts. if ( ! $defer ) { wp_update_term_count( null, null, true ); } @@ -3069,8 +3204,6 @@ * * @since 2.3.0 * - * @staticvar array $_deferred - * * @param int|array $terms The term_taxonomy_id of the terms. * @param string $taxonomy The context of the term. * @param bool $do_deferred Whether to flush the deferred term counts too. Default false. @@ -3128,11 +3261,11 @@ } } - if ( $object_types == array_filter( $object_types, 'post_type_exists' ) ) { - // Only post types are attached to this taxonomy + if ( array_filter( $object_types, 'post_type_exists' ) == $object_types ) { + // Only post types are attached to this taxonomy. _update_post_term_count( $terms, $taxonomy ); } else { - // Default count updater + // Default count updater. _update_generic_term_count( $terms, $taxonomy ); } } @@ -3143,7 +3276,7 @@ } // -// Cache +// Cache. // /** @@ -3193,16 +3326,16 @@ } /** - * Will remove all of the term ids from the cache. + * Will remove all of the term IDs from the cache. * * @since 2.3.0 * - * @global wpdb $wpdb WordPress database abstraction object. + * @global wpdb $wpdb WordPress database abstraction object. * @global bool $_wp_suspend_cache_invalidation * - * @param int|array $ids Single or list of Term IDs. - * @param string $taxonomy Optional. Can be empty and will assume `tt_ids`, else will use for context. - * Default empty. + * @param int|int[] $ids Single or array of term IDs. + * @param string $taxonomy Optional. Taxonomy slug. Can be empty, in which case the taxonomies of the passed + * term IDs will be used. Default empty. * @param bool $clean_taxonomy Optional. Whether to clean taxonomy wide caches (true), or just individual * term object caches (false). Default true. */ @@ -3224,14 +3357,17 @@ $tt_ids = implode( ', ', $tt_ids ); $terms = $wpdb->get_results( "SELECT term_id, taxonomy FROM $wpdb->term_taxonomy WHERE term_taxonomy_id IN ($tt_ids)" ); $ids = array(); + foreach ( (array) $terms as $term ) { $taxonomies[] = $term->taxonomy; $ids[] = $term->term_id; wp_cache_delete( $term->term_id, 'terms' ); } + $taxonomies = array_unique( $taxonomies ); } else { $taxonomies = array( $taxonomy ); + foreach ( $taxonomies as $taxonomy ) { foreach ( $ids as $id ) { wp_cache_delete( $id, 'terms' ); @@ -3286,21 +3422,21 @@ } /** - * Retrieves the taxonomy relationship to the term object id. + * Retrieves the cached term objects for the given object ID. * * Upstream functions (like get_the_terms() and is_object_in_term()) are * responsible for populating the object-term relationship cache. The current * function only fetches relationship data that is already in the cache. * * @since 2.3.0 - * @since 4.7.0 Returns a `WP_Error` object if `get_term()` returns an error for + * @since 4.7.0 Returns a `WP_Error` object if there's an error with * any of the matched terms. * - * @param int $id Term object ID. + * @param int $id Term object ID, for example a post, comment, or user ID. * @param string $taxonomy Taxonomy name. - * @return bool|array|WP_Error Array of `WP_Term` objects, if cached. - * False if cache is empty for `$taxonomy` and `$id`. - * WP_Error if get_term() returns an error object for any term. + * @return bool|WP_Term[]|WP_Error Array of `WP_Term` objects, if cached. + * False if cache is empty for `$taxonomy` and `$id`. + * WP_Error if get_term() returns an error object for any term. */ function get_object_term_cache( $id, $taxonomy ) { $_term_ids = wp_cache_get( $id, "{$taxonomy}_relationships" ); @@ -3348,8 +3484,8 @@ * * @since 2.3.0 * - * @param string|array $object_ids Comma-separated list or array of term object IDs. - * @param array|string $object_type The taxonomy object type. + * @param string|int[] $object_ids Comma-separated list or array of term object IDs. + * @param string|string[] $object_type The taxonomy object type or array of the same. * @return void|false False if all of the terms in `$object_ids` are already cached. */ function update_object_term_cache( $object_ids, $object_type ) { @@ -3361,26 +3497,29 @@ $object_ids = explode( ',', $object_ids ); } - $object_ids = array_map( 'intval', $object_ids ); + $object_ids = array_map( 'intval', $object_ids ); + $non_cached_ids = array(); $taxonomies = get_object_taxonomies( $object_type ); - $ids = array(); - foreach ( (array) $object_ids as $id ) { - foreach ( $taxonomies as $taxonomy ) { - if ( false === wp_cache_get( $id, "{$taxonomy}_relationships" ) ) { - $ids[] = $id; - break; + foreach ( $taxonomies as $taxonomy ) { + $cache_values = wp_cache_get_multiple( (array) $object_ids, "{$taxonomy}_relationships" ); + + foreach ( $cache_values as $id => $value ) { + if ( false === $value ) { + $non_cached_ids[] = $id; } } } - if ( empty( $ids ) ) { + if ( empty( $non_cached_ids ) ) { return false; } + $non_cached_ids = array_unique( $non_cached_ids ); + $terms = wp_get_object_terms( - $ids, + $non_cached_ids, $taxonomies, array( 'fields' => 'all_with_object_id', @@ -3394,7 +3533,7 @@ $object_terms[ $term->object_id ][ $term->taxonomy ][] = $term->term_id; } - foreach ( $ids as $id ) { + foreach ( $non_cached_ids as $id ) { foreach ( $taxonomies as $taxonomy ) { if ( ! isset( $object_terms[ $id ][ $taxonomy ] ) ) { if ( ! isset( $object_terms[ $id ] ) ) { @@ -3417,8 +3556,8 @@ * * @since 2.3.0 * - * @param array $terms List of term objects to change. - * @param string $taxonomy Optional. Update Term to this taxonomy in cache. Default empty. + * @param WP_Term[] $terms Array of term objects to change. + * @param string $taxonomy Not used. */ function update_term_cache( $terms, $taxonomy = '' ) { foreach ( (array) $terms as $term ) { @@ -3433,7 +3572,7 @@ } // -// Private +// Private. // /** @@ -3456,8 +3595,8 @@ } $children = array(); $terms = get_terms( - $taxonomy, array( + 'taxonomy' => $taxonomy, 'get' => 'all', 'orderby' => 'id', 'fields' => 'id=>parent', @@ -3499,10 +3638,11 @@ return $empty_array; } + $term_id = (int) $term_id; $term_list = array(); $has_children = _get_term_hierarchy( $taxonomy ); - if ( ( 0 != $term_id ) && ! isset( $has_children[ $term_id ] ) ) { + if ( $term_id && ! isset( $has_children[ $term_id ] ) ) { return $empty_array; } @@ -3526,7 +3666,7 @@ continue; } - if ( $term->parent == $term_id ) { + if ( (int) $term->parent === $term_id ) { if ( $use_id ) { $term_list[] = $term->term_id; } else { @@ -3539,7 +3679,8 @@ $ancestors[ $term->term_id ] = 1; - if ( $children = _get_term_children( $term->term_id, $terms, $taxonomy, $ancestors ) ) { + $children = _get_term_children( $term->term_id, $terms, $taxonomy, $ancestors ); + if ( $children ) { $term_list = array_merge( $term_list, $children ); } } @@ -3585,12 +3726,14 @@ $term_ids[ $term->term_taxonomy_id ] = $term->term_id; } - // Get the object and term ids and stick them in a lookup table. + // Get the object and term IDs and stick them in a lookup table. $tax_obj = get_taxonomy( $taxonomy ); $object_types = esc_sql( $tax_obj->object_type ); $results = $wpdb->get_results( "SELECT object_id, term_taxonomy_id FROM $wpdb->term_relationships INNER JOIN $wpdb->posts ON object_id = ID WHERE term_taxonomy_id IN (" . implode( ',', array_keys( $term_ids ) ) . ") AND post_type IN ('" . implode( "', '", $object_types ) . "') AND post_status = 'publish'" ); + foreach ( $results as $row ) { - $id = $term_ids[ $row->term_taxonomy_id ]; + $id = $term_ids[ $row->term_taxonomy_id ]; + $term_items[ $id ][ $row->object_id ] = isset( $term_items[ $id ][ $row->object_id ] ) ? ++$term_items[ $id ][ $row->object_id ] : 1; } @@ -3600,14 +3743,16 @@ $ancestors = array(); while ( ! empty( $terms_by_id[ $child ] ) && $parent = $terms_by_id[ $child ]->parent ) { $ancestors[] = $child; + if ( ! empty( $term_items[ $term_id ] ) ) { foreach ( $term_items[ $term_id ] as $item_id => $touches ) { $term_items[ $parent ][ $item_id ] = isset( $term_items[ $parent ][ $item_id ] ) ? ++$term_items[ $parent ][ $item_id ] : 1; } } + $child = $parent; - if ( in_array( $parent, $ancestors ) ) { + if ( in_array( $parent, $ancestors, true ) ) { break; } } @@ -3648,7 +3793,7 @@ } // -// Default callbacks +// Default callbacks. // /** @@ -3662,8 +3807,8 @@ * * @global wpdb $wpdb WordPress database abstraction object. * - * @param array $terms List of Term taxonomy IDs. - * @param object $taxonomy Current taxonomy object of terms. + * @param int[] $terms List of Term taxonomy IDs. + * @param WP_Taxonomy $taxonomy Current taxonomy object of terms. */ function _update_post_term_count( $terms, $taxonomy ) { global $wpdb; @@ -3676,7 +3821,8 @@ $object_types = array_unique( $object_types ); - if ( false !== ( $check_attachments = array_search( 'attachment', $object_types ) ) ) { + $check_attachments = array_search( 'attachment', $object_types, true ); + if ( false !== $check_attachments ) { unset( $object_types[ $check_attachments ] ); $check_attachments = true; } @@ -3694,6 +3840,7 @@ } if ( $object_types ) { + // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.QuotedDynamicPlaceholderGeneration $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 ) ); } @@ -3715,8 +3862,8 @@ * * @global wpdb $wpdb WordPress database abstraction object. * - * @param array $terms List of term taxonomy IDs. - * @param object $taxonomy Current taxonomy object of terms. + * @param int[] $terms List of term taxonomy IDs. + * @param WP_Taxonomy $taxonomy Current taxonomy object of terms. */ function _update_generic_term_count( $terms, $taxonomy ) { global $wpdb; @@ -3770,7 +3917,7 @@ } // If there are no shared term_taxonomy rows, there's nothing to do here. - $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 ) ); + $shared_tt_count = (int) $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 ) ); if ( ! $shared_tt_count ) { return $term_id; @@ -3780,8 +3927,8 @@ * Verify that the term_taxonomy_id passed to the function is actually associated with the term_id. * If there's a mismatch, it may mean that the term is already split. Return the actual term_id from the db. */ - $check_term_id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $term_taxonomy_id ) ); - if ( $check_term_id != $term_id ) { + $check_term_id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $term_taxonomy_id ) ); + if ( $check_term_id !== $term_id ) { return $check_term_id; } @@ -3944,7 +4091,8 @@ // Split term data recording is slow, so we do it just once, outside the loop. $split_term_data = get_option( '_split_terms', array() ); - $skipped_first_term = $taxonomies = array(); + $skipped_first_term = array(); + $taxonomies = array(); foreach ( $shared_tts as $shared_tt ) { $term_id = intval( $shared_tt->term_id ); @@ -4003,12 +4151,12 @@ * @param string $taxonomy Taxonomy for the split term. */ function _wp_check_split_default_terms( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) { - if ( 'category' != $taxonomy ) { + if ( 'category' !== $taxonomy ) { return; } foreach ( array( 'default_category', 'default_link_category', 'default_email_category' ) as $option ) { - if ( $term_id == get_option( $option, -1 ) ) { + if ( (int) get_option( $option, -1 ) === $term_id ) { update_option( $option, $new_term_id ); } } @@ -4069,7 +4217,7 @@ // Update menu locations. $locations = get_nav_menu_locations(); foreach ( $locations as $location => $menu_id ) { - if ( $term_id == $menu_id ) { + if ( $term_id === $menu_id ) { $locations[ $location ] = $new_term_id; } } @@ -4146,11 +4294,11 @@ * * @since 2.5.0 * - * @global WP_Rewrite $wp_rewrite - * - * @param object|int|string $term The term object, ID, or slug whose link will be retrieved. - * @param string $taxonomy Optional. Taxonomy. Default empty. - * @return string|WP_Error HTML link to taxonomy term archive on success, WP_Error if term does not exist. + * @global WP_Rewrite $wp_rewrite WordPress rewrite component. + * + * @param WP_Term|int|string $term The term object, ID, or slug whose link will be retrieved. + * @param string $taxonomy Optional. Taxonomy. Default empty. + * @return string|WP_Error URL of the taxonomy term archive on success, WP_Error if term does not exist. */ function get_term_link( $term, $taxonomy = '' ) { global $wp_rewrite; @@ -4189,7 +4337,7 @@ $t = get_taxonomy( $taxonomy ); if ( empty( $termlink ) ) { - if ( 'category' == $taxonomy ) { + if ( 'category' === $taxonomy ) { $termlink = '?cat=' . $term->term_id; } elseif ( $t->query_var ) { $termlink = "?$t->query_var=$slug"; @@ -4213,26 +4361,29 @@ } $termlink = home_url( user_trailingslashit( $termlink, 'category' ) ); } - // Back Compat filters. - if ( 'post_tag' == $taxonomy ) { + + // Back compat filters. + if ( 'post_tag' === $taxonomy ) { /** * Filters the tag link. * * @since 2.3.0 - * @deprecated 2.5.0 Use 'term_link' instead. + * @since 2.5.0 Deprecated in favor of {@see 'term_link'} filter. + * @since 5.4.1 Restored (un-deprecated). * * @param string $termlink Tag link URL. * @param int $term_id Term ID. */ $termlink = apply_filters( 'tag_link', $termlink, $term->term_id ); - } elseif ( 'category' == $taxonomy ) { + } elseif ( 'category' === $taxonomy ) { /** * Filters the category link. * * @since 1.5.0 - * @deprecated 2.5.0 Use 'term_link' instead. + * @since 2.5.0 Deprecated in favor of {@see 'term_link'} filter. + * @since 5.4.1 Restored (un-deprecated). * * @param string $termlink Category link URL. * @param int $term_id Term ID. @@ -4245,9 +4396,9 @@ * * @since 2.5.0 * - * @param string $termlink Term link URL. - * @param object $term Term object. - * @param string $taxonomy Taxonomy slug. + * @param string $termlink Term link URL. + * @param WP_Term $term Term object. + * @param string $taxonomy Taxonomy slug. */ return apply_filters( 'term_link', $termlink, $term, $taxonomy ); } @@ -4279,9 +4430,9 @@ 'after' => '', ); - $r = wp_parse_args( $args, $defaults ); - - echo $r['before'] . join( $r['sep'], get_the_taxonomies( $r['post'], $r ) ) . $r['after']; + $parsed_args = wp_parse_args( $args, $defaults ); + + echo $parsed_args['before'] . join( $parsed_args['sep'], get_the_taxonomies( $parsed_args['post'], $parsed_args ) ) . $parsed_args['after']; } /** @@ -4293,8 +4444,8 @@ * @since 2.5.0 * * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. - * @param array $args { - * Optional. Arguments about how to format the list of taxonomies. Default empty array. + * @param array $args { + * Optional. Arguments about how to format the list of taxonomies. Default empty array. * * @type string $template Template for displaying a taxonomy label and list of terms. * Default is "Label: Terms." @@ -4309,7 +4460,7 @@ $args = wp_parse_args( $args, array( - /* translators: %s: taxonomy label, %l: list of terms formatted as per $term_template */ + /* translators: %s: Taxonomy label, %l: List of terms formatted as per $term_template. */ 'template' => __( '%s: %l.' ), 'term_template' => '%2$s', ) @@ -4353,12 +4504,12 @@ } /** - * Retrieve all taxonomies of a post with just the names. + * Retrieve all taxonomy names for the given post. * * @since 2.5.0 * * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. - * @return array An array of all taxonomy names for the given post. + * @return string[] An array of all taxonomy names for the given post. */ function get_post_taxonomies( $post = 0 ) { $post = get_post( $post ); @@ -4381,7 +4532,8 @@ * @return bool|WP_Error WP_Error on input error. */ function is_object_in_term( $object_id, $taxonomy, $terms = null ) { - if ( ! $object_id = (int) $object_id ) { + $object_id = (int) $object_id; + if ( ! $object_id ) { return new WP_Error( 'invalid_object', __( 'Invalid object ID.' ) ); } @@ -4407,7 +4559,8 @@ $terms = (array) $terms; - if ( $ints = array_filter( $terms, 'is_int' ) ) { + $ints = array_filter( $terms, 'is_int' ); + if ( $ints ) { $strs = array_diff( $terms, $ints ); } else { $strs =& $terms; @@ -4415,7 +4568,7 @@ foreach ( $object_terms as $object_term ) { // If term is an int, check against term_ids only. - if ( $ints && in_array( $object_term->term_id, $ints ) ) { + if ( $ints && in_array( $object_term->term_id, $ints, true ) ) { return true; } @@ -4426,10 +4579,10 @@ return true; } - if ( in_array( $object_term->name, $strs ) ) { + if ( in_array( $object_term->name, $strs, true ) ) { return true; } - if ( in_array( $object_term->slug, $strs ) ) { + if ( in_array( $object_term->slug, $strs, true ) ) { return true; } } @@ -4452,7 +4605,7 @@ if ( empty( $taxonomies ) ) { return false; } - return in_array( $taxonomy, $taxonomies ); + return in_array( $taxonomy, $taxonomies, true ); } /** @@ -4466,7 +4619,7 @@ * ancestors. Accepts a post type or a taxonomy name. Default empty. * @param string $resource_type Optional. Type of resource $object_type is. Accepts 'post_type' * or 'taxonomy'. Default empty. - * @return array An array of ancestors from lowest to highest in the hierarchy. + * @return int[] An array of IDs of ancestors from lowest to highest in the hierarchy. */ function get_ancestors( $object_id = 0, $object_type = '', $resource_type = '' ) { $object_id = (int) $object_id; @@ -4489,7 +4642,7 @@ if ( 'taxonomy' === $resource_type ) { $term = get_term( $object_id, $object_type ); - while ( ! is_wp_error( $term ) && ! empty( $term->parent ) && ! in_array( $term->parent, $ancestors ) ) { + while ( ! is_wp_error( $term ) && ! empty( $term->parent ) && ! in_array( $term->parent, $ancestors, true ) ) { $ancestors[] = (int) $term->parent; $term = get_term( $term->parent, $object_type ); } @@ -4503,7 +4656,7 @@ * @since 3.1.0 * @since 4.1.1 Introduced the `$resource_type` parameter. * - * @param array $ancestors An array of object ancestors. + * @param int[] $ancestors An array of IDs of object ancestors. * @param int $object_id Object ID. * @param string $object_type Type of object. * @param string $resource_type Type of resource $object_type is. @@ -4539,23 +4692,23 @@ * @param int $parent `term_id` of the parent for the term we're checking. * @param int $term_id The term we're checking. * @param string $taxonomy The taxonomy of the term we're checking. - * * @return int The new parent for the term. */ function wp_check_term_hierarchy_for_loops( $parent, $term_id, $taxonomy ) { - // Nothing fancy here - bail + // Nothing fancy here - bail. if ( ! $parent ) { return 0; } // Can't be its own parent. - if ( $parent == $term_id ) { + if ( $parent === $term_id ) { return 0; } // Now look for larger loops. - if ( ! $loop = wp_find_hierarchy_loop( 'wp_get_term_taxonomy_parent_id', $term_id, $parent, array( $taxonomy ) ) ) { - return $parent; // No loop + $loop = wp_find_hierarchy_loop( 'wp_get_term_taxonomy_parent_id', $term_id, $parent, array( $taxonomy ) ); + if ( ! $loop ) { + return $parent; // No loop. } // Setting $parent to the given value causes a loop.