WordPress.org

Make WordPress Core

Opened 4 years ago

Closed 3 years ago

#27918 closed defect (bug) (wontfix)

get_taxonomies() on single post type should return taxonomies registered on multiple post types

Reported by: johnrork Owned by:
Milestone: Priority: normal
Severity: normal Version: 3.0
Component: Taxonomy Keywords: needs-unit-tests needs-refresh needs-patch
Focuses: Cc:

Description

A taxonomy registered on multiple post types is missing from get_taxonomies() when called with only one of those post types.

It seems self-evident that get_taxonomies should return all of a post type's taxonomies, regardless of how they were registered.

//... on init...
register_taxonomy('foo', array('bar','baz'), $opts);

//... in template ...
// returns taxonomies registered only on 'bar', 'foo' is missing
get_taxonomies('object_type'=>array('bar')); 

// returns 'foo' only if exact array is passed
get_taxonomies('object_type'=>array('bar','baz')); 

Attachments (3)

27918.diff (854 bytes) - added by bobbingwide 4 years ago.
wp_list_filter() cater for $m_value being an array
27918.2.diff (868 bytes) - added by andg 3 years ago.
Checking if both the key and the value are arrays, and attempt to perform an intersection between them.
27918.3.diff (1.9 KB) - added by boonebgorges 3 years ago.

Download all attachments as: .zip

Change History (17)

#1 @SergeyBiryukov
4 years ago

  • Component changed from General to Taxonomy

#2 @wonderboymusic
4 years ago

  • Keywords needs-patch needs-unit-tests added
  • Milestone changed from Awaiting Review to 4.0

johnrork, thanks for the report, sounds like we need to investigate this and write some unit tests

#3 @bobbingwide
4 years ago

I'm at a WordPress Contributor day in Sheffield. I've developed a fix for this problem. Patch coming soon but basically it's this. In wp_list_filter() replace the second foreach loop to

foreach ( $args as $m_key => $m_value ) {
	if ( array_key_exists( $m_key, $to_match ) && $m_value == $to_match[ $m_key ] )
		$matched++;
}

to cater for $m_value being an array.

foreach ( $args as $m_key => $m_value ) {
        if ( array_key_exists( $m_key, $to_match ) ) {
          if ( $m_value == $to_match[ $m_key ] ) {
  	    $matched++;
          }
          elseif ( is_array( $m_value ) && is_array( $to_match[ $m_key ] ) ) {
            foreach ( $m_value as $mv_key => $mv_value ) {
              if ( in_array( $mv_value, $to_match[ $m_key ] ) ) {
                $matched = $count;
              }
            }
}

We also check that $to_match[ $m_key ] is an array before checking for the presence of each given value ( $mv_value ). If ANY of the fields is found then the value of $matched is set to $count so that the following tests on the operator will pass. Note: I haven't tested with different values of operator - just used default 'AND'.

I developed a shortcode to test the changes. With no parameters passed it returns a list of all registered post types with each of their taxonomy names. With a post_types=a,b,c parameter the list of taxonomies returned is the set of taxonomies associated with any of the post types.

e.g. for post,page it returns category post_tag post_format for page,post,nav_menu_item,revision is returns category post_tag nav_menu post_format

@bobbingwide
4 years ago

wp_list_filter() cater for $m_value being an array

#4 @Denis-de-Bernardy
4 years ago

Note that you can use get_object_taxonomies() in the meanwhile.

#5 @pauldewouters
4 years ago

The call to get_taxonomies should be:

get_taxonomies(
		array(
			'object_type' => array( 'post' ),

		)
	)

I have an alternative fix:

		foreach ( $args as $m_key => $m_value ) {
			if ( array_key_exists( $m_key, $to_match ) && ( $m_value == $to_match[ $m_key ] ) || ( is_array( $m_value ) && array_key_exists( $m_key, $to_match ) ) )
				$matched++;
		}

#6 @wonderboymusic
4 years ago

  1. Whitespace is strange, may be your editor...
  2. Unit tests, please

This ticket was mentioned in IRC in #wordpress-dev by DrewAPicture. View the logs.


4 years ago

#8 @DrewAPicture
4 years ago

  • Keywords needs-refresh has-patch added; needs-patch removed
  • Milestone changed from 4.0 to Future Release

Sounds like we still need a refresh and unit tests here. Punting.

#9 @johnbillion
4 years ago

  • Version changed from trunk to 3.0

#10 @andg
3 years ago

Alternatively, you can check if both the key and the value are arrays, and perform an array_intersect on them. In the get_taxonomies use case, this would allow to find taxonomies that belong to more than one post type (they're excluded from the results now).

@andg
3 years ago

Checking if both the key and the value are arrays, and attempt to perform an intersection between them.

#11 @boonebgorges
3 years ago

  • Keywords needs-patch added; has-patch removed

What are we going to break by making wp_list_filter() match partially like this? I agree that the change makes sense for get_taxonomies(), but I can think of plenty of cases where you may only want to match the full array.

A more local fix is probably appropriate here. In get_taxonomies(), if we detect that 'object_type' is an array, we may want to run a separate wp_list_filter() on it, using the 'OR' operator.

@boonebgorges
3 years ago

#12 follow-up: @boonebgorges
3 years ago

Kinda like [27918.3.diff].

#13 in reply to: ↑ 12 @andg
3 years ago

Replying to boonebgorges:

Kinda like [27918.3.diff].

That might work. Came up with an almost identical solution.

#14 @boonebgorges
3 years ago

  • Milestone Future Release deleted
  • Resolution set to wontfix
  • Status changed from new to closed

So, I've been thinking this over some more. In the same way that making a general change to wp_list_filter() will break certain legitimate filters, my suggested fix will make it impossible to do certain legitimate filters on taxonomies. What if I want to find all the taxonomies that are exclusive to 'post'?

More generally, the suggested change breaks the general pattern of functions that use wp_list_filter() internally, by treating one of the filters as a special case. I think that's a bad idea.

As noted in 4,get_object_taxonomies() is really meant for this very purpose, so it should be used instead.

Note: See TracTickets for help on using tickets.