: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @param int $term Term ID.
* @param string $taxonomy Taxonomy name.
* @param array|string $args {
* Optional. Array of arguments to override the default term ID. Default empty array.
* @type int $default The term ID to make the default term. This will only override
* the terms found if there is only one term found. Any other and
* the found terms are used.
* @type bool $force_default Optional. Whether to force the supplied term as default to be
* assigned even if the object was not going to be term-less.
* @return bool|int|WP_Error True on success, false if term does not exist. Zero on attempted
* deletion of default Category. WP_Error if the taxonomy does not exist.
function wp_delete_term( $term, $taxonomy, $args = array() ) {
$ids = term_exists( $term, $taxonomy );
if ( is_wp_error( $ids ) ) {
$tt_id = $ids['term_taxonomy_id'];
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 ) {
$args = wp_parse_args( $args, $defaults );
if ( isset( $args['default'] ) ) {
$default = (int) $args['default'];
if ( ! term_exists( $default, $taxonomy ) ) {
if ( isset( $args['force_default'] ) ) {
$force_default = $args['force_default'];
* Fires when deleting a term, before any modifications are made to posts or terms.
* @param int $term Term ID.
* @param string $taxonomy Taxonomy name.
do_action( 'pre_delete_term', $term, $taxonomy );
// Update children to point to new parent.
if ( is_taxonomy_hierarchical( $taxonomy ) ) {
$term_obj = get_term( $term, $taxonomy );
if ( is_wp_error( $term_obj ) ) {
$parent = $term_obj->parent;
$edit_ids = $wpdb->get_results( "SELECT term_id, term_taxonomy_id FROM $wpdb->term_taxonomy WHERE `parent` = " . (int) $term_obj->term_id );
$edit_tt_ids = wp_list_pluck( $edit_ids, 'term_taxonomy_id' );
* Fires immediately before a term to delete's children are reassigned a parent.
* @param array $edit_tt_ids An array of term taxonomy IDs for the given term.
do_action( 'edit_term_taxonomies', $edit_tt_ids );
$wpdb->update( $wpdb->term_taxonomy, compact( 'parent' ), array( 'parent' => $term_obj->term_id ) + compact( 'taxonomy' ) );
// Clean the cache for all child terms.
$edit_term_ids = wp_list_pluck( $edit_ids, 'term_id' );
clean_term_cache( $edit_term_ids, $taxonomy );
* Fires immediately after a term to delete's children are reassigned a parent.
* @param array $edit_tt_ids An array of term taxonomy IDs for the given term.
do_action( 'edited_term_taxonomies', $edit_tt_ids );
// Get the term before deleting it or its term relationships so we can pass to actions below.
$deleted_term = get_term( $term, $taxonomy );
$object_ids = (array) $wpdb->get_col( $wpdb->prepare( "SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $tt_id ) );
foreach ( $object_ids as $object_id ) {
if ( ! isset( $default ) ) {
wp_remove_object_terms( $object_id, $term, $taxonomy );
$terms = wp_get_object_terms(
if ( 1 === count( $terms ) && isset( $default ) ) {
$terms = array( $default );
$terms = array_diff( $terms, array( $term ) );
if ( isset( $default ) && isset( $force_default ) && $force_default ) {
$terms = array_merge( $terms, array( $default ) );
$terms = array_map( 'intval', $terms );
wp_set_object_terms( $object_id, $terms, $taxonomy );
// Clean the relationship caches for all object types using this term.
$tax_object = get_taxonomy( $taxonomy );
foreach ( $tax_object->object_type as $object_type ) {
clean_object_term_cache( $object_ids, $object_type );
$term_meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->termmeta WHERE term_id = %d ", $term ) );
foreach ( $term_meta_ids as $mid ) {
delete_metadata_by_mid( 'term', $mid );
* Fires immediately before a term taxonomy ID is deleted.
* @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 ) );
* Fires immediately after a term taxonomy ID is deleted.
* @param int $tt_id Term taxonomy ID.
do_action( 'deleted_term_taxonomy', $tt_id );
// Delete the term if no taxonomies use it.
if ( ! $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy WHERE term_id = %d", $term ) ) ) {
$wpdb->delete( $wpdb->terms, array( 'term_id' => $term ) );
clean_term_cache( $term, $taxonomy );
* Fires after a term is deleted from the database and the cache is cleaned.
* The {@see 'delete_$taxonomy'} hook is also available for targeting a specific
* @since 4.5.0 Introduced the `$object_ids` argument.
* @param int $term Term ID.
* @param int $tt_id Term taxonomy ID.
* @param string $taxonomy Taxonomy slug.
* @param WP_Term $deleted_term Copy of the already-deleted term.
* @param array $object_ids List of term object IDs.
do_action( 'delete_term', $term, $tt_id, $taxonomy, $deleted_term, $object_ids );
* Fires after a term in a specific taxonomy is deleted.
* The dynamic portion of the hook name, `$taxonomy`, refers to the specific
* taxonomy the term belonged to.
* Possible hook names include:
* @since 4.5.0 Introduced the `$object_ids` argument.
* @param int $term Term ID.
* @param int $tt_id Term taxonomy ID.
* @param WP_Term $deleted_term Copy of the already-deleted term.
* @param array $object_ids List of term object IDs.
do_action( "delete_{$taxonomy}", $term, $tt_id, $deleted_term, $object_ids );
* Deletes one existing category.
* @param int $cat_id Category term ID.
* @return bool|int|WP_Error Returns true if completes delete action; false if term doesn't exist;
* Zero on attempted deletion of default Category; WP_Error object is
function wp_delete_category( $cat_id ) {
return wp_delete_term( $cat_id, 'category' );
* Retrieves the terms associated with the given object(s), in the supplied taxonomies.
* @since 4.2.0 Added support for 'taxonomy', 'parent', and 'term_taxonomy_id' values of `$orderby`.
* Introduced `$parent` argument.
* @since 4.4.0 Introduced `$meta_query` and `$update_term_meta_cache` arguments. When `$fields` is 'all' or
* '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.
* @since 6.3.0 Passing `update_term_meta_cache` argument value false by default resulting in get_terms() to not
* prime the term meta cache.
* @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 WP_Term[]|int[]|string[]|string|WP_Error Array of terms, a count thereof as a numeric string,
* or WP_Error if any of the taxonomies do not exist.
* See WP_Term_Query::get_terms() for more information.
function wp_get_object_terms( $object_ids, $taxonomies, $args = array() ) {
if ( empty( $object_ids ) || empty( $taxonomies ) ) {
if ( ! is_array( $taxonomies ) ) {
$taxonomies = array( $taxonomies );
foreach ( $taxonomies as $taxonomy ) {
if ( ! taxonomy_exists( $taxonomy ) ) {
return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
if ( ! is_array( $object_ids ) ) {
$object_ids = array( $object_ids );
$object_ids = array_map( 'intval', $object_ids );
'update_term_meta_cache' => false,
$args = wp_parse_args( $args, $defaults );
* Filters arguments for retrieving object terms.
* @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 );
* When one or more queried taxonomies is registered with an 'args' array,
* those params override the `$args` passed to this function.
if ( count( $taxonomies ) > 1 ) {
foreach ( $taxonomies as $index => $taxonomy ) {
$t = get_taxonomy( $taxonomy );
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 ) ) );
$t = get_taxonomy( $taxonomies[0] );
if ( isset( $t->args ) && is_array( $t->args ) ) {
$args = array_merge( $args, $t->args );
$args['taxonomy'] = $taxonomies;
$args['object_ids'] = $object_ids;
// Taxonomies registered without an 'args' param are handled here.
if ( ! empty( $taxonomies ) ) {
$terms_from_remaining_taxonomies = get_terms( $args );
// Array keys should be preserved for values of $fields that use term_id for keys.
if ( ! empty( $args['fields'] ) && str_starts_with( $args['fields'], 'id=>' ) ) {
$terms = $terms + $terms_from_remaining_taxonomies;
$terms = array_merge( $terms, $terms_from_remaining_taxonomies );
* Filters the terms for a given object or objects.
* @param WP_Term[]|int[]|string[]|string $terms Array of terms or a count thereof as a numeric string.
* @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 );
$object_ids = implode( ',', $object_ids );
$taxonomies = "'" . implode( "', '", array_map( 'esc_sql', $taxonomies ) ) . "'";
* Filters the terms for a given object or objects.
* The `$taxonomies` parameter passed to this filter is formatted as a SQL fragment. The
* {@see 'get_object_terms'} filter is recommended as an alternative.
* @param WP_Term[]|int[]|string[]|string $terms Array of terms or a count thereof as a numeric string.
* @param string $object_ids Comma separated list of object IDs for which terms were retrieved.
* @param string $taxonomies SQL fragment 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 );
* Adds a new term to the database.
* A non-existent term is inserted in the following sequence:
* 1. The term is added to the term table, then related to the taxonomy.
* 2. If everything is correct, several actions are fired.
* 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`.
* 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
* If the taxonomy is hierarchical, and the 'parent' argument is not empty,
* the term is inserted and the term_id will be given.
* 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,
* or the term slug and name are not unique, a WP_Error object will be returned.
* @global wpdb $wpdb WordPress database abstraction object.
* @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 query string of arguments for inserting 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 of the new term data, WP_Error otherwise.
* @type int $term_id The new term ID.
* @type int|string $term_taxonomy_id The new term taxonomy ID. Can be a numeric string.
function wp_insert_term( $term, $taxonomy, $args = array() ) {
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 6.1.0 The `$args` parameter was added.
* @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.
* @param array|string $args Array or query string of arguments passed to wp_insert_term().
$term = apply_filters( 'pre_insert_term', $term, $taxonomy, $args );
if ( is_wp_error( $term ) ) {
if ( is_int( $term ) && 0 === $term ) {
return new WP_Error( 'invalid_term_id', __( 'Invalid term ID.' ) );
if ( '' === trim( $term ) ) {
return new WP_Error( 'empty_term_name', __( 'A name is required for this term.' ) );
$args = wp_parse_args( $args, $defaults );
if ( (int) $args['parent'] > 0 && ! term_exists( (int) $args['parent'] ) ) {
return new WP_Error( 'missing_parent', __( 'Parent term does not exist.' ) );
$args['taxonomy'] = $taxonomy;
// Coerce null description to strings, to avoid database errors.
$args['description'] = (string) $args['description'];
$args = sanitize_term( $args, $taxonomy, 'db' );
// expected_slashed ($name)
$name = wp_unslash( $args['name'] );
$description = wp_unslash( $args['description'] );
$parent = (int) $args['parent'];
// Sanitization could clean the name to an empty string that must be checked again.
return new WP_Error( 'invalid_term_name', __( 'Invalid term name.' ) );
$slug_provided = ! empty( $args['slug'] );
if ( ! $slug_provided ) {
$slug = sanitize_title( $name );
if ( $args['alias_of'] ) {
$alias = get_term_by( 'slug', $args['alias_of'], $taxonomy );
if ( ! empty( $alias->term_group ) ) {
// The alias we want is already in a group, so let's use that one.
$term_group = $alias->term_group;
} elseif ( ! empty( $alias->term_id ) ) {
* The alias is not in a group, so we create a new one
* and add the alias to it.
$term_group = $wpdb->get_var( "SELECT MAX(term_group) FROM $wpdb->terms" ) + 1;
'term_group' => $term_group,
* Prevent the creation of terms with duplicate names at the same level of a taxonomy hierarchy,
* unless a unique slug has been explicitly provided.