WordPress.org

Make WordPress Core

Opened 5 years ago

Closed 5 years ago

Last modified 5 years ago

#34175 closed defect (bug) (wontfix)

Add correlating get_fields_terms filter for get_terms

Reported by: wpsmith Owned by:
Milestone: Priority: normal
Severity: normal Version: 4.4
Component: Taxonomy Keywords:
Focuses: Cc:

Description

Currently, there is a filter (get_terms_fields) to filter the fields to select in the terms query. I believe that the use of this filter could be easily expanded to involve additional return types. So I would like to introduce a filter (get_terms_fields_terms) for the return $_terms that would only be called if $_fields is not one of the already pre-defined options (i.e., all, id=>parent, ids, names, id=>name, id=>slug).

While someone could possibly use get_terms to do this manipulation, the specified/default query will still execute and be cached, and there is no way to really do what one wants to do without having to re-do the entire function, which in my opinion is not preferable. Also modifying the get_terms_fields will modify the cached results of all queries with the same taxonomies and arguments.

It is noted in the filter (get_terms_fields) documentation that "Use of this filter can result in unpredictable behavior, and is not recommended." Based on my limited testing, I found that changing the return fields (e.g., array( 't.slug', 't.name', 'tt.count', 'tt.taxonomy' )) via get_terms_fields causes the following issues:

  • If you do not change the default fields argument or use all, PHP throws an error with updating the cache (update_term_cache called because 'all' == $_fields and there is no check for the term ID there or within update_term_cache since update_term_cache rightly assumes that $terms is an array of term objects).
    • Notice: Undefined property: stdClass::$term_id ...
  • If you use one of the following pre-defined examples, id=>parent, ids, id=>name, id=>slug), each of these will throw an error if get_terms_fields removes the term_id ('t.term_id').
    • Notice: Undefined property: stdClass::$term_id ...
  • If using all and wanting pad_counts, another error is thrown by _pad_term_counts which assumes the first parameter is an array of term objects (not IDs, see #34174).
  • If you are trying to get a term list of a specific parent (e.g., $child_of), more errors persist as _get_term_children (which calls get_term) also assumes that $terms is an array of term objects (like update_term_cache) or an integer (term_id). This is perpetuated even further by utilization of expected object members (e.g., $term->parent);
  • If you are trying to hide empty terms (hide_empty) this causes another error as it also assumes that $terms is an array of term objects.
  • If you are passing in update_term_meta_cache then $term_ids = wp_list_pluck( $terms, 'term_id' ); causes another error as does update_termmeta_cache.
  • Potential errors within themes & plugins

A possible solution is to patch wp_pluck_list (#34172) & add checks using wp_pluck_list (see patch).

Attachments (4)

34175.taxonomy-functions.php.patch (2.6 KB) - added by wpsmith 5 years ago.
Checks
34175.get_terms_fields_terms.taxonomy-functions.php.patch (471 bytes) - added by wpsmith 5 years ago.
get_terms_fields_terms filter
34175.get_terms_fields_terms.2.taxonomy-functions.php.patch (1.4 KB) - added by wpsmith 5 years ago.
It should be noted that if considered, then get_terms_fields_terms will need documentation.
34175.get_terms_fields_terms.3.taxonomy-functions.php.patch (1.4 KB) - added by wpsmith 5 years ago.
Replace previous. Typo in filter docs.

Download all attachments as: .zip

Change History (7)

@wpsmith
5 years ago

get_terms_fields_terms filter

@wpsmith
5 years ago

It should be noted that if considered, then get_terms_fields_terms will need documentation.

@wpsmith
5 years ago

Replace previous. Typo in filter docs.

#1 @wpsmith
5 years ago

Here is an example use of the additional filter: https://gist.github.com/wpsmith/f153b7ab746417d73b7d

#2 @boonebgorges
5 years ago

  • Milestone Awaiting Review deleted
  • Resolution set to wontfix
  • Status changed from new to closed

get_terms_fields was introduced in [11037]. See #9004.

get_terms_fields is an unpleasant filter. It has been juggled around in various places in get_terms() through the years in such a way that it's surprise it works for anyone anymore. I'd like to remove it altogether. But there are probably some people who have managed to make it work (after a fashion) and they should continue to be able to do so. Anyway, I do not want to make a bunch of changes to get_terms() just so that people can more easily use this old filter, especially when improper use of the filter breaks the cache strategy of get_terms().

Your proposed get_terms_fields_terms filter doesn't do anything that you couldn't already do by processing the results of get_terms() using wp_list_pluck() or a foreach loop. If you need to do it via filter, use 'get_terms'.

Also, the way the filter is currently placed means that it breaks caching in get_terms(). Let's say you have the following:

function wp34175_customize_get_terms_output( $terms ) {
    if ( is_page() ) {
        return wp_list_pluck( $terms, 'name' );
    } else {
        return $terms;
    }
}
add_filter( 'get_terms_fields_terms', 'wp34175_customize_get_terms_output' );

If you call it first on a page, the value added to the cache will be an array of names. If you later call it outside of a page context using the same params, you'll be given the same array of names, even though you wanted term objects.

For more background on the relationship between 'get_terms_fields', the fields param, and the get_terms() cache, see #31174. In the meantime, for your purposes, use the get_terms filter.

#3 @wpsmith
5 years ago

  • Focuses performance removed

As a result, let's consider deprecating the hook. Ref. #34195

Note: See TracTickets for help on using tickets.