#35493 closed defect (bug) (fixed)
get_terms does not return correct value when a term is searched by a name containing a single quote
| Reported by: |
|
Owned by: |
|
|---|---|---|---|
| Milestone: | 4.5 | Priority: | normal |
| Severity: | normal | Version: | 4.3 |
| Component: | Taxonomy | Keywords: | |
| Focuses: | Cc: |
Description
get_terms() function does not return correct value when a term is searched by a name containing a single quote ('). Apparently the terms name get escaped twice.
To reproduce it, first add one tag with name containing ', like Chef d'oeuvre, then use this function:
$name = "Chef d'oeuvre";
$terms = get_terms('post_tag', array(
'name' => $name,
'hide_empty' => false
));
var_dump($terms); // array(0) { }
I think the problem lies in /wp-includes/taxonomy.php, lines 1296-1301 (https://core.trac.wordpress.org/browser/tags/4.4/src/wp-includes/taxonomy.php#L1296):
$names = (array) $args['name'];
var_dump($names); // array(1) { [0]=> string(13) "Chef d'oeuvre" }
foreach ( $names as &$_name ) {
$_name = sanitize_term_field( 'name', $_name, 0, reset( $taxonomies ), 'db' );
}
var_dump($names); // array(1) { [0]=> &string(14) "Chef d\'oeuvre" }
$where .= " AND t.name IN ('" . implode( "', '", array_map( 'esc_sql', $names ) ) . "')";
var_dump($where ); // "tt.taxonomy IN ('post_tag') AND t.name IN ('Chef d\\\'oeuvre')"
I'd suggest to just remove the last esc_sql formatting, but I am not sure if it may lead to other problems.
Change History (3)
Note: See
TracTickets for help on using
tickets.
@maximeschoeni Welcome to WordPress Trac! Thanks for the detailed report.
I've confirmed the issue, and traced it to [32353]. In that changeset, we switched from sanitizing using
sanitize_text_field()on the value ofnameto usingsanitize_term_field( 'name' ). This change was necessary because terms go through thesanitize_term_field()filter when being saved in the first place, so that terms names are run through a couple different sanitization routines before being stored in the database.One thing that
sanitize_term_field( 'name' )does is run the$namethroughwp_filter_kses(). This function runsstripslashes()on the value passed to it, and then runsaddslashes()to it again before returning it. This is becausewp_filter_kses()expects slashed data. Butget_terms()expects the 'name' param to be unslashed already; see egWP_Terms_List_Table::prepare_items(), where the search term is unslashed before being passed toget_terms().Technically, the
addslashes()performed bywp_filter_kses()does the same thing as the call toesc_sql()that you've pointed out. But this is partially an accident of howwp_filter_kses()- a function that was not designed for MySQL escaping - was designed. So, for developer clarity, it's probably wiser to keep the lateesc_sql()escaping as-is but remove slashes on what's returned fromsanitize_term_field().