Make WordPress Core

Changeset 63488


Ignore:
Timestamp:
09/05/2026 01:39:01 AM (5 weeks ago)
Author:
westonruter
Message:

Taxonomy: Fix wp_get_object_terms() when requesting a count.

Requesting a count passed the numeric string get_terms() returns straight to array_merge(), which warns and yields null on PHP 7.4 and throws a TypeError on PHP 8.0 and later. The count is now cast before it is merged, and summed once every taxonomy has been queried, so the function returns the numeric string its documentation has described since r49947. An empty object or taxonomy list returns '0' for the same reason, rather than the empty array that contradicted the documented type.

A taxonomy registered with an args array is queried by a separate recursive call, and those results were merged with array_merge() unconditionally. For the id=> values of fields the term IDs are integer array keys, which array_merge() renumbers, so such a taxonomy came back keyed from zero. The recursive branch now uses the union operator for those, as the merge for the remaining taxonomies has done since r41809.

The functions get_terms(), wp_get_object_terms(), wp_count_terms(), wp_get_post_categories(), wp_get_post_tags() and wp_get_post_terms() each gain a conditional return type that resolves the result from the fields value, falling back to what that function's own default answers with, as was done for WP_Term_Query::query() in r63358.

Developed in ​https://github.com/WordPress/wordpress-develop/pull/7278.
Follow-up to r38667, r40513, r41809, r49947, r63358.

Props marian1, westonruter, swissspidy.
See #65817, #66049.
Fixes #61936.

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/post.php

    r63442 r63488  
    44534453 * @param array $args    Optional. Category query parameters. Default empty array.
    44544454 *                       See WP_Term_Query::__construct() for supported arguments.
    4455  * @return array|WP_Error List of categories. If the `$fields` argument passed via `$args` is 'all' or
    4456  *                        'all_with_object_id', an array of WP_Term objects will be returned. If `$fields`
    4457  *                        is 'ids', an array of category IDs. If `$fields` is 'names', an array of category names.
    4458  *                        WP_Error object if 'category' taxonomy doesn't exist.
     4455 * @return int[]|WP_Term[]|string[]|string|WP_Error List of categories. An array of category IDs by
     4456 *                                                  default, and if the `$fields` argument passed via
     4457 *                                                  `$args` is 'ids'. If `$fields` is 'all' or
     4458 *                                                  'all_with_object_id', an array of WP_Term objects.
     4459 *                                                  If `$fields` is 'names', an array of category names.
     4460 *                                                  If `$fields` is 'count', a count thereof as a numeric
     4461 *                                                  string. WP_Error object if 'category' taxonomy
     4462 *                                                  doesn't exist.
     4463 *
     4464 * @phpstan-return (
     4465 *     $args is array{ fields: 'count', ... }
     4466 *         ? numeric-string|WP_Error
     4467 *         : ( $args is array{ fields: 'id=>parent', ... }
     4468 *             ? array<int, int>|WP_Error
     4469 *             : ( $args is array{ fields: 'names'|'slugs', ... }
     4470 *                 ? string[]|WP_Error
     4471 *                 : ( $args is array{ fields: 'id=>name'|'id=>slug', ... }
     4472 *                     ? array<int, string>|WP_Error
     4473 *                     : ( $args is array{ fields: 'all'|'all_with_object_id', ... }
     4474 *                         ? WP_Term[]|WP_Error
     4475 *                         : int[]|WP_Error ) ) ) )
     4476 * )
    44594477 */
    44604478function wp_get_post_categories( $post_id = 0, $args = array() ) {
    … …  
    44814499 * @param array $args    Optional. Tag query parameters. Default empty array.
    44824500 *                       See WP_Term_Query::__construct() for supported arguments.
    4483  * @return array|WP_Error Array of WP_Term objects on success or empty array if no tags were found.
    4484  *                        WP_Error object if 'post_tag' taxonomy doesn't exist.
     4501 * @return WP_Term[]|int[]|string[]|string|WP_Error Array of WP_Term objects on success or empty array if no
     4502 *                                                  tags were found. A count thereof as a numeric string if
     4503 *                                                  the `$fields` argument passed via `$args` is 'count'.
     4504 *                                                  WP_Error object if 'post_tag' taxonomy doesn't exist.
     4505 *
     4506 * @phpstan-return (
     4507 *     $args is array{ fields: 'count', ... }
     4508 *         ? numeric-string|WP_Error
     4509 *         : ( $args is array{ fields: 'ids'|'tt_ids', ... }
     4510 *             ? int[]|WP_Error
     4511 *             : ( $args is array{ fields: 'id=>parent', ... }
     4512 *                 ? array<int, int>|WP_Error
     4513 *                 : ( $args is array{ fields: 'names'|'slugs', ... }
     4514 *                     ? string[]|WP_Error
     4515 *                     : ( $args is array{ fields: 'id=>name'|'id=>slug', ... }
     4516 *                         ? array<int, string>|WP_Error
     4517 *                         : WP_Term[]|WP_Error ) ) ) )
     4518 * )
    44854519 */
    44864520function wp_get_post_tags( $post_id = 0, $args = array() ) {
    … …  
    45024536 *     @type string $fields Term fields to retrieve. Default 'all'.
    45034537 * }
    4504  * @return array|WP_Error Array of WP_Term objects on success or empty array if no terms were found.
    4505  *                        WP_Error object if `$taxonomy` doesn't exist.
     4538 * @return WP_Term[]|int[]|string[]|string|WP_Error Array of WP_Term objects on success or empty array if no
     4539 *                                                  terms were found. A count thereof as a numeric string if
     4540 *                                                  the `$fields` argument passed via `$args` is 'count'.
     4541 *                                                  WP_Error object if `$taxonomy` doesn't exist.
     4542 *
     4543 * @phpstan-return (
     4544 *     $args is array{ fields: 'count', ... }
     4545 *         ? numeric-string|WP_Error
     4546 *         : ( $args is array{ fields: 'ids'|'tt_ids', ... }
     4547 *             ? int[]|WP_Error
     4548 *             : ( $args is array{ fields: 'id=>parent', ... }
     4549 *                 ? array<int, int>|WP_Error
     4550 *                 : ( $args is array{ fields: 'names'|'slugs', ... }
     4551 *                     ? string[]|WP_Error
     4552 *                     : ( $args is array{ fields: 'id=>name'|'id=>slug', ... }
     4553 *                         ? array<int, string>|WP_Error
     4554 *                         : WP_Term[]|WP_Error ) ) ) )
     4555 * )
    45064556 */
    45074557function wp_get_post_terms( $post_id = 0, $taxonomy = 'post_tag', $args = array() ) {
  • trunk/src/wp-includes/taxonomy.php

    r63426 r63488  
    13101310 * @since 4.8.0 Introduced 'suppress_filter' parameter.
    13111311 *
    1312  * @param array|string $args       Optional. Array or string of arguments. See WP_Term_Query::__construct()
     1312 * @param array|string $args       Optional. Array or string of arguments. See {@see WP_Term_Query::__construct()}
    13131313 *                                 for information on accepted arguments. Default empty array.
    13141314 * @param array|string $deprecated Optional. Argument array, when using the legacy function parameter format.
    … …  
    13161316 *                                 function parameter will be parsed as a taxonomy or array of taxonomies.
    13171317 *                                 Default empty.
    1318  * @return WP_Term[]|int[]|string[]|string|WP_Error Array of terms, a count thereof as a numeric string,
    1319  *                                                  or WP_Error if any of the taxonomies do not exist.
    1320  *                                                  See the function description for more information.
     1318 * @return WP_Term[]|int[]|string[]|int|string|WP_Error Array of terms, a count thereof as a numeric string,
     1319 *                                                      the integer 0 when the queried parent term is not in
     1320 *                                                      the taxonomy hierarchy, or WP_Error if any of the
     1321 *                                                      taxonomies do not exist. See the function description
     1322 *                                                      for more information.
     1323 *
     1324 * @phpstan-return (
     1325 *     $args is array{ fields: 'count', ... }
     1326 *         ? 0|numeric-string|WP_Error
     1327 *         : ( $args is array{ fields: 'ids'|'tt_ids', ... }
     1328 *             ? int[]|WP_Error
     1329 *             : ( $args is array{ fields: 'id=>parent', ... }
     1330 *                 ? array<int, int>|WP_Error
     1331 *                 : ( $args is array{ fields: 'names'|'slugs', ... }
     1332 *                     ? string[]|WP_Error
     1333 *                     : ( $args is array{ fields: 'id=>name'|'id=>slug', ... }
     1334 *                         ? array<int, string>|WP_Error
     1335 *                         : ( $deprecated is ''
     1336 *                             ? ( $args is array
     1337 *                                 ? WP_Term[]|WP_Error
     1338 *                                 : WP_Term[]|int[]|string[]|int|string|WP_Error )
     1339 *                             : WP_Term[]|int[]|string[]|int|string|WP_Error ) ) ) ) )
     1340 * )
    13211341 */
    13221342function get_terms( $args = array(), $deprecated = '' ) {
    … …  
    19581978 * @since 5.6.0 Changed the function signature so that the `$args` array can be provided as the first parameter.
    19591979 *
    1960  * @param array|string $args       Optional. Array or string of arguments. See WP_Term_Query::__construct()
     1980 * @param array|string $args       Optional. Array or string of arguments. See {@see WP_Term_Query::__construct()}
    19611981 *                                 for information on accepted arguments. Default empty array.
    19621982 * @param array|string $deprecated Optional. Argument array, when using the legacy function parameter format.
    … …  
    19641984 *                                 function parameter will be parsed as a taxonomy or array of taxonomies.
    19651985 *                                 Default empty.
    1966  * @return string|WP_Error Numeric string containing the number of terms in that
    1967  *                         taxonomy or WP_Error if the taxonomy does not exist.
     1986 * @return string|int|WP_Error Numeric string containing the number of terms in that taxonomy,
     1987 *                             the integer 0 when the queried parent term is not in the taxonomy
     1988 *                             hierarchy, or WP_Error if the taxonomy does not exist.
     1989 * @phpstan-return numeric-string|0|WP_Error
    19681990 */
    19691991function wp_count_terms( $args = array(), $deprecated = '' ) {
    … …  
    19932015        }
    19942016
    1995         $args['fields'] = 'count';
     2017        $args = array_merge(
     2018                $args,
     2019                array( 'fields' => 'count' )
     2020        );
    19962021
    19972022        return get_terms( $args );
    … …  
    22902315 * @since 6.3.0 Passing `update_term_meta_cache` argument value false by default resulting in get_terms() to not
    22912316 *              prime the term meta cache.
     2317 * @since 7.2.0 A count is returned as a numeric string when `$fields` is 'count'. Previously requesting
     2318 *              a count resulted in an error.
    22922319 *
    22932320 * @param int|int[]       $object_ids The ID(s) of the object(s) to retrieve.
    22942321 * @param string|string[] $taxonomies The taxonomy names to retrieve terms from.
    2295  * @param array|string    $args       See WP_Term_Query::__construct() for supported arguments.
     2322 * @param array|string    $args       See {@see WP_Term_Query::__construct()} for supported arguments.
    22962323 * @return WP_Term[]|int[]|string[]|string|WP_Error Array of terms, a count thereof as a numeric string,
    22972324 *                                                  or WP_Error if any of the taxonomies do not exist.
    2298  *                                                  See WP_Term_Query::get_terms() for more information.
     2325 *                                                  See {@see WP_Term_Query::get_terms()} for more information.
     2326 *
     2327 * @phpstan-return (
     2328 *     $args is array{ fields: 'count', ... }
     2329 *         ? numeric-string|WP_Error
     2330 *         : ( $args is array{ fields: 'ids'|'tt_ids', ... }
     2331 *             ? int[]|WP_Error
     2332 *             : ( $args is array{ fields: 'id=>parent', ... }
     2333 *                 ? array<int, int>|WP_Error
     2334 *                 : ( $args is array{ fields: 'names'|'slugs', ... }
     2335 *                     ? string[]|WP_Error
     2336 *                     : ( $args is array{ fields: 'id=>name'|'id=>slug', ... }
     2337 *                         ? array<int, string>|WP_Error
     2338 *                         : ( $args is array
     2339 *                             ? WP_Term[]|WP_Error
     2340 *                             : WP_Term[]|int[]|string[]|string|WP_Error ) ) ) ) )
     2341 * )
    22992342 */
    23002343function wp_get_object_terms( $object_ids, $taxonomies, $args = array() ) {
     2344        $args = wp_parse_args( $args );
     2345
    23012346        if ( empty( $object_ids ) || empty( $taxonomies ) ) {
     2347                if ( isset( $args['fields'] ) && 'count' === $args['fields'] ) {
     2348                        return '0';
     2349                }
     2350
    23022351                return array();
    23032352        }
    … …  
    23392388         * When one or more queried taxonomies is registered with an 'args' array,
    23402389         * those params override the `$args` passed to this function.
     2390         *
     2391         * That array is for query modifiers such as 'orderby'. Overriding 'fields'
     2392         * there does not work, because callers depend on the shape they asked for:
     2393         * get_the_taxonomies() reads `$term->name` off the result, and
     2394         * wp_set_object_terms() needs the 'tt_ids' it requested. A taxonomy that
     2395         * overrides it also returns a different shape than the taxonomies queried
     2396         * below, leaving the two merged into one another here.
    23412397         */
    23422398        $terms = array();
    … …  
    23462402                        if ( isset( $t->args ) && is_array( $t->args ) && array_merge( $args, $t->args ) != $args ) {
    23472403                                unset( $taxonomies[ $index ] );
    2348                                 $terms = array_merge( $terms, wp_get_object_terms( $object_ids, $taxonomy, array_merge( $args, $t->args ) ) );
     2404
     2405                                // Cast because a count is returned as a numeric string. The counts are summed below.
     2406                                $terms_from_taxonomy = (array) wp_get_object_terms( $object_ids, $taxonomy, array_merge( $args, $t->args ) );
     2407
     2408                                // Array keys should be preserved for values of $fields that use term_id for keys.
     2409                                if ( ! empty( $args['fields'] ) && str_starts_with( $args['fields'], 'id=>' ) ) {
     2410                                        $terms = $terms + $terms_from_taxonomy;
     2411                                } else {
     2412                                        $terms = array_merge( $terms, $terms_from_taxonomy );
     2413                                }
    23492414                        }
    23502415                }
    … …  
    23612426        // Taxonomies registered without an 'args' param are handled here.
    23622427        if ( ! empty( $taxonomies ) ) {
    2363                 $terms_from_remaining_taxonomies = get_terms( $args );
     2428                // Cast because a count is returned as a numeric string. The counts are summed below.
     2429                $terms_from_remaining_taxonomies = (array) get_terms( $args );
    23642430
    23652431                // Array keys should be preserved for values of $fields that use term_id for keys.
    … …  
    23712437        }
    23722438
     2439        if ( isset( $args['fields'] ) && 'count' === $args['fields'] ) {
     2440                $terms = (string) array_sum( $terms );
     2441        }
     2442
    23732443        /**
    23742444         * Filters the terms for a given object or objects.
    … …  
    23802450         * @param string[]                        $taxonomies Array of taxonomy names from which terms were retrieved.
    23812451         * @param array                           $args       Array of arguments for retrieving terms for the given
    2382          *                                                    object(s). See wp_get_object_terms() for details.
     2452         *                                                    object(s). See {@see wp_get_object_terms()} for details.
    23832453         */
    23842454        $terms = apply_filters( 'get_object_terms', $terms, $object_ids, $taxonomies, $args );
    … …  
    23992469         * @param string                          $taxonomies SQL fragment of taxonomy names from which terms were retrieved.
    24002470         * @param array                           $args       Array of arguments for retrieving terms for the given
    2401          *                                                    object(s). See wp_get_object_terms() for details.
     2471         *                                                    object(s). See {@see wp_get_object_terms()} for details.
    24022472         */
    24032473        return apply_filters( 'wp_get_object_terms', $terms, $object_ids, $taxonomies, $args );
  • trunk/tests/phpstan/baselines/property.nonObject.neon

    r63383 r63488  
    2525                        path: ../../../src/wp-admin/includes/ajax-actions.php
    2626                -
    27                         message: '#^Cannot access property \$id on int\|string\|WP_Term\.$#'
    28                         identifier: property.nonObject
    29                         count: 1
    30                         path: ../../../src/wp-admin/includes/ajax-actions.php
    31                 -
    32                         message: '#^Cannot access property \$link on int\|string\|WP_Term\.$#'
    33                         identifier: property.nonObject
    34                         count: 1
    35                         path: ../../../src/wp-admin/includes/ajax-actions.php
    36                 -
    3727                        message: '#^Cannot access property \$name on array\|object\.$#'
    3828                        identifier: property.nonObject
  • trunk/tests/phpstan/baselines/property.notFound.neon

    r63367 r63488  
    2020        ignoreErrors:
    2121                -
     22                        message: '#^Access to an undefined property WP_Term\:\:\$id\.$#'
     23                        identifier: property.notFound
     24                        count: 1
     25                        path: ../../../src/wp-admin/includes/ajax-actions.php
     26                -
     27                        message: '#^Access to an undefined property WP_Term\:\:\$link\.$#'
     28                        identifier: property.notFound
     29                        count: 1
     30                        path: ../../../src/wp-admin/includes/ajax-actions.php
     31                -
    2232                        message: '#^Access to an undefined property WP_Upgrader_Skin\:\:\$language_update\.$#'
    2333                        identifier: property.notFound
  • trunk/tests/phpunit/tests/term.php

    r56971 r63488  
    7878                // There are 5 posts, all Uncategorized.
    7979                $this->assertSame( '1', $count );
     80        }
     81
     82        /**
     83         * Ensures a queried parent term outside the taxonomy hierarchy counts as the integer 0.
     84         *
     85         * Every other outcome is a numeric string, so this is the one case where the return
     86         * type is not a string at all.
     87         *
     88         * @ticket 61936
     89         *
     90         * @covers ::wp_count_terms
     91         */
     92        public function test_wp_count_terms_should_return_integer_zero_for_a_parent_outside_the_hierarchy() {
     93                register_taxonomy( 'wptests_tax_hierarchical', 'post', array( 'hierarchical' => true ) );
     94
     95                $term_id = self::factory()->term->create( array( 'taxonomy' => 'wptests_tax_hierarchical' ) );
     96                $this->assertIsInt( $term_id, 'The term was not created.' );
     97
     98                $count = wp_count_terms(
     99                        array(
     100                                'taxonomy' => 'wptests_tax_hierarchical',
     101                                'parent'   => 99999,
     102                        )
     103                );
     104                $this->assertSame( 0, $count, 'Incorrect count for a parent outside the hierarchy.' );
     105
     106                $count = wp_count_terms(
     107                        array(
     108                                'taxonomy' => 'wptests_tax_hierarchical',
     109                                'child_of' => 99999,
     110                        )
     111                );
     112                $this->assertSame( 0, $count, 'Incorrect count for a child_of outside the hierarchy.' );
    80113        }
    81114
  • trunk/tests/phpunit/tests/term/wpGetObjectTerms.php

    r62751 r63488  
    66 */
    77class Tests_Term_WpGetObjectTerms extends WP_UnitTestCase {
    8         private $taxonomy = 'wptests_tax';
     8        /**
     9         * Name of the taxonomy registered for each test.
     10         */
     11        private string $taxonomy = 'wptests_tax';
    912
    1013        /**
    … …  
    1215         *
    1316         * Used in the `test_taxonomies_passed_to_wp_get_object_terms_filter_should_be_quoted()` method.
    14          *
    15          * @var array
    16          */
    17         private $taxonomies;
     17         * This is a SQL fragment of taxonomy names from which terms were retrieved.
     18         */
     19        private ?string $taxonomies = null;
    1820
    1921        public function set_up() {
    … …  
    2628         */
    2729        public function tear_down() {
    28                 unset( $this->taxonomies );
     30                $this->taxonomies = null;
    2931
    3032                parent::tear_down();
    … …  
    10131015                $this->assertSameSets( $expected, $actual );
    10141016        }
     1017
     1018        /**
     1019         * @ticket 61936
     1020         */
     1021        public function test_should_return_numeric_string_for_fields_count() {
     1022                $fields = array( 'fields' => 'count' );
     1023
     1024                $taxonomies = array( 'wptests_tax', 'wptests_tax_2' );
     1025
     1026                register_taxonomy( $taxonomies[0], 'post' );
     1027                register_taxonomy( $taxonomies[1], 'post' );
     1028
     1029                $term_1_id = self::factory()->term->create( array( 'taxonomy' => $taxonomies[0] ) );
     1030                $term_2_id = self::factory()->term->create( array( 'taxonomy' => $taxonomies[1] ) );
     1031
     1032                $post_ids = self::factory()->post->create_many( 2 );
     1033                wp_set_object_terms( $post_ids[0], $term_1_id, $taxonomies[0] );
     1034                wp_set_object_terms( $post_ids[1], $term_1_id, $taxonomies[0] );
     1035                wp_set_object_terms( $post_ids[1], $term_2_id, $taxonomies[1] );
     1036
     1037                $terms_count = wp_get_object_terms( 0, $taxonomies[0], $fields );
     1038                $this->assertSame( '0', $terms_count, 'Incorrect term count with empty object_ids.' );
     1039
     1040                $terms_count = wp_get_object_terms( $post_ids[0], '', $fields );
     1041                $this->assertSame( '0', $terms_count, 'Incorrect term count with empty taxonomies.' );
     1042
     1043                $terms_count = wp_get_object_terms( $post_ids[0], $taxonomies[0], $fields );
     1044                $this->assertSame( '1', $terms_count, 'Incorrect term count with single object_id and single taxonomy.' );
     1045
     1046                $terms_count = wp_get_object_terms( $post_ids[0], $taxonomies, $fields );
     1047                $this->assertSame( '1', $terms_count, 'Incorrect term count with single object_id and multiple taxonomies.' );
     1048
     1049                $terms_count = wp_get_object_terms( $post_ids[1], $taxonomies, $fields );
     1050                $this->assertSame( '2', $terms_count, 'Incorrect term count with single object_id and multiple taxonomies.' );
     1051
     1052                $terms_count = wp_get_object_terms( $post_ids, $taxonomies, $fields );
     1053                $this->assertSame( '3', $terms_count, 'Incorrect term count with multiple object_ids and multiple taxonomies.' );
     1054        }
     1055
     1056        /**
     1057         * Ensures that a count can be requested with the `$args` parameter in query string form.
     1058         *
     1059         * An empty object ID or taxonomy list short-circuits before `$args` would otherwise be
     1060         * parsed, so the query string has to be parsed up front for the `fields` value to be read.
     1061         *
     1062         * @ticket 61936
     1063         */
     1064        public function test_should_return_numeric_string_for_fields_count_passed_as_query_string() {
     1065                $post_id = self::factory()->post->create();
     1066                $this->assertIsInt( $post_id, 'The post was not created.' );
     1067
     1068                $term_id = self::factory()->term->create( array( 'taxonomy' => $this->taxonomy ) );
     1069                $this->assertIsInt( $term_id, 'The term was not created.' );
     1070
     1071                wp_set_object_terms( $post_id, $term_id, $this->taxonomy );
     1072
     1073                $terms_count = wp_get_object_terms( 0, $this->taxonomy, 'fields=count' );
     1074                $this->assertSame( '0', $terms_count, 'Incorrect term count with empty object_ids.' );
     1075
     1076                $terms_count = wp_get_object_terms( $post_id, '', 'fields=count' );
     1077                $this->assertSame( '0', $terms_count, 'Incorrect term count with empty taxonomies.' );
     1078
     1079                $terms_count = wp_get_object_terms( $post_id, $this->taxonomy, 'fields=count' );
     1080                $this->assertSame( '1', $terms_count, 'Incorrect term count.' );
     1081        }
     1082
     1083        /**
     1084         * Ensures that a count is summed across a taxonomy registered with an 'args' array.
     1085         *
     1086         * Such a taxonomy is queried by a recursive call rather than alongside the others,
     1087         * and that call returns the count as a numeric string rather than as an array.
     1088         *
     1089         * @ticket 61936
     1090         */
     1091        public function test_should_return_numeric_string_for_fields_count_with_taxonomy_registered_with_args() {
     1092                $taxonomy1 = 'wptests_tax';
     1093                $taxonomy2 = 'wptests_tax_2';
     1094
     1095                // Any non-empty 'args' array sends the taxonomy down the recursive path.
     1096                register_taxonomy( $taxonomy1, 'post', array( 'args' => array( 0 ) ) );
     1097                register_taxonomy( $taxonomy2, 'post' );
     1098
     1099                $post_id = self::factory()->post->create();
     1100                $this->assertIsInt( $post_id, 'The post was not created.' );
     1101
     1102                $term_1_id = self::factory()->term->create( array( 'taxonomy' => $taxonomy1 ) );
     1103                $this->assertIsInt( $term_1_id, 'The term in the first taxonomy was not created.' );
     1104
     1105                $term_2_id = self::factory()->term->create( array( 'taxonomy' => $taxonomy2 ) );
     1106                $this->assertIsInt( $term_2_id, 'The term in the second taxonomy was not created.' );
     1107
     1108                wp_set_object_terms( $post_id, $term_1_id, $taxonomy1 );
     1109                wp_set_object_terms( $post_id, $term_2_id, $taxonomy2 );
     1110
     1111                $terms_count = wp_get_object_terms( $post_id, $taxonomy1, array( 'fields' => 'count' ) );
     1112                $this->assertSame( '1', $terms_count, 'Incorrect term count with the single taxonomy registered with args.' );
     1113
     1114                $terms_count = wp_get_object_terms( $post_id, array( $taxonomy1, $taxonomy2 ), array( 'fields' => 'count' ) );
     1115                $this->assertSame( '2', $terms_count, 'Incorrect term count across both taxonomies.' );
     1116        }
     1117
     1118        /**
     1119         * Verifies that the `id=>` values of the `fields` argument key the results by term ID.
     1120         *
     1121         * These are the values for which the results are merged with `+` rather than with
     1122         * array_merge(), so that the term ID keys survive.
     1123         *
     1124         * @ticket 61936
     1125         */
     1126        public function test_should_return_terms_keyed_by_term_id_for_id_fields() {
     1127                register_taxonomy( 'wptests_tax_hierarchical', 'post', array( 'hierarchical' => true ) );
     1128
     1129                $parent_id = self::factory()->term->create(
     1130                        array(
     1131                                'taxonomy' => 'wptests_tax_hierarchical',
     1132                                'name'     => 'Parent',
     1133                                'slug'     => 'parent',
     1134                        )
     1135                );
     1136                $this->assertIsInt( $parent_id, 'The parent term was not created.' );
     1137
     1138                $child_id = self::factory()->term->create(
     1139                        array(
     1140                                'taxonomy' => 'wptests_tax_hierarchical',
     1141                                'name'     => 'Child',
     1142                                'slug'     => 'child',
     1143                                'parent'   => $parent_id,
     1144                        )
     1145                );
     1146                $this->assertIsInt( $child_id, 'The child term was not created.' );
     1147
     1148                $post_id = self::factory()->post->create();
     1149                $this->assertIsInt( $post_id, 'The post was not created.' );
     1150
     1151                wp_set_object_terms( $post_id, array( $parent_id, $child_id ), 'wptests_tax_hierarchical' );
     1152
     1153                $expected = array(
     1154                        'id=>parent' => array(
     1155                                $parent_id => 0,
     1156                                $child_id  => $parent_id,
     1157                        ),
     1158                        'id=>name'   => array(
     1159                                $parent_id => 'Parent',
     1160                                $child_id  => 'Child',
     1161                        ),
     1162                        'id=>slug'   => array(
     1163                                $parent_id => 'parent',
     1164                                $child_id  => 'child',
     1165                        ),
     1166                );
     1167
     1168                foreach ( $expected as $fields => $expected_terms ) {
     1169                        $actual = wp_get_object_terms(
     1170                                $post_id,
     1171                                'wptests_tax_hierarchical',
     1172                                array(
     1173                                        'fields'  => $fields,
     1174                                        'orderby' => 'term_id',
     1175                                        'order'   => 'ASC',
     1176                                )
     1177                        );
     1178
     1179                        $this->assertSame( $expected_terms, $actual, "Incorrect terms for the '$fields' fields value." );
     1180                }
     1181        }
     1182
     1183        /**
     1184         * Ensures the term ID keys survive for a taxonomy registered with an 'args' array.
     1185         *
     1186         * Such a taxonomy is queried by a recursive call, and those results were merged with
     1187         * array_merge(), which renumbers the integer keys the `id=>` values rely on.
     1188         *
     1189         * @ticket 61936
     1190         */
     1191        public function test_should_return_terms_keyed_by_term_id_for_id_fields_with_taxonomy_registered_with_args() {
     1192                $taxonomy1 = 'wptests_tax';
     1193                $taxonomy2 = 'wptests_tax_2';
     1194
     1195                // Any non-empty 'args' array sends the taxonomy down the recursive path.
     1196                register_taxonomy( $taxonomy1, 'post', array( 'args' => array( 0 ) ) );
     1197                register_taxonomy( $taxonomy2, 'post' );
     1198
     1199                $post_id = self::factory()->post->create();
     1200                $this->assertIsInt( $post_id, 'The post was not created.' );
     1201
     1202                $term_1_id = self::factory()->term->create(
     1203                        array(
     1204                                'taxonomy' => $taxonomy1,
     1205                                'name'     => 'Alpha',
     1206                        )
     1207                );
     1208                $this->assertIsInt( $term_1_id, 'The term in the first taxonomy was not created.' );
     1209
     1210                $term_2_id = self::factory()->term->create(
     1211                        array(
     1212                                'taxonomy' => $taxonomy2,
     1213                                'name'     => 'Beta',
     1214                        )
     1215                );
     1216                $this->assertIsInt( $term_2_id, 'The term in the second taxonomy was not created.' );
     1217
     1218                wp_set_object_terms( $post_id, $term_1_id, $taxonomy1 );
     1219                wp_set_object_terms( $post_id, $term_2_id, $taxonomy2 );
     1220
     1221                $actual = wp_get_object_terms(
     1222                        $post_id,
     1223                        array( $taxonomy1, $taxonomy2 ),
     1224                        array( 'fields' => 'id=>name' )
     1225                );
     1226
     1227                $expected = array(
     1228                        $term_1_id => 'Alpha',
     1229                        $term_2_id => 'Beta',
     1230                );
     1231
     1232                $this->assertSame( $expected, $actual, 'Terms are not keyed by term ID.' );
     1233        }
    10151234}
Note: See TracChangeset for help on using the changeset viewer.