In `wp_insert_term()`, clean up accidental duplicate terms after insert.
In [30056], the UNIQUE index was removed from the 'slug' column of `wp_terms`. While we have numerous checks in place to avoid the creation of unwanted duplicate term+term_taxonomy pairs, it's possible that in certain edge cases - such as during the lag caused by database replication, or a race condition involving near-simultaneous creation of more than one term - we'll end up unwittingly inserting two identical rows. The current changeset minimizes this risk by introducing a failsafe mechanism into `wp_insert_term()`. After a term and term_taxonomy are INSERTed, we check to see whether the term just created is a duplicate of an existing term; if so, we delete the new one and keep the old one. This prevents problems caused by replication lag, because SELECT queries that take place after an INSERT will hit the master database; it mitigates race conditions by enforcing that the term that was created first (ie, the one with the lowest `term_id`) is always the "canonical" one. Props nacin, markjaquith. See #22023, #5809. Built from https://develop.svn.wordpress.org/trunk@30238 git-svn-id: http://core.svn.wordpress.org/trunk@30238 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
1483e80848
commit
4ce9db9ce8
|
@ -2902,6 +2902,24 @@ function wp_insert_term( $term, $taxonomy, $args = array() ) {
|
||||||
$wpdb->insert( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent') + array( 'count' => 0 ) );
|
$wpdb->insert( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent') + array( 'count' => 0 ) );
|
||||||
$tt_id = (int) $wpdb->insert_id;
|
$tt_id = (int) $wpdb->insert_id;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sanity check: if we just created a term with the same parent + taxonomy + slug but a higher term_id than
|
||||||
|
* an existing term, then we have unwittingly created a duplicate term. Delete the dupe, and use the term_id
|
||||||
|
* and term_taxonomy_id of the older term instead. Then return out of the function so that the "create" hooks
|
||||||
|
* are not fired.
|
||||||
|
*/
|
||||||
|
$duplicate_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.term_id, tt.term_taxonomy_id FROM $wpdb->terms t INNER JOIN $wpdb->term_taxonomy tt ON ( tt.term_id = t.term_id ) WHERE t.slug = %s AND tt.parent = %d AND tt.taxonomy = %s AND t.term_id < %d AND tt.term_taxonomy_id != %d", $slug, $parent, $taxonomy, $term_id, $tt_id ) );
|
||||||
|
if ( $duplicate_term ) {
|
||||||
|
$wpdb->delete( $wpdb->terms, array( 'term_id' => $term_id ) );
|
||||||
|
$wpdb->delete( $wpdb->term_taxonomy, array( 'term_taxonomy_id' => $tt_id ) );
|
||||||
|
|
||||||
|
$term_id = (int) $duplicate_term->term_id;
|
||||||
|
$tt_id = (int) $duplicate_term->term_taxonomy_id;
|
||||||
|
|
||||||
|
clean_term_cache( $term_id, $taxonomy );
|
||||||
|
return array( 'term_id' => $term_id, 'term_taxonomy_id' => $tt_id );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fires immediately after a new term is created, before the term cache is cleaned.
|
* Fires immediately after a new term is created, before the term cache is cleaned.
|
||||||
*
|
*
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
*
|
*
|
||||||
* @global string $wp_version
|
* @global string $wp_version
|
||||||
*/
|
*/
|
||||||
$wp_version = '4.1-alpha-30237';
|
$wp_version = '4.1-alpha-30238';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||||
|
|
Loading…
Reference in New Issue