WordPress.org

Make WordPress Core

Changeset 36485


Ignore:
Timestamp:
02/06/2016 04:41:26 AM (5 years ago)
Author:
boonebgorges
Message:

Allow get_terms() results to ordered by metadata.

The $orderby parameter of get_terms() now accepts the following values,
related to term meta:

  • 'meta_value'
  • 'meta_value_num'
  • the value of the $meta_key parameter
  • any key from the $meta_query array

This brings order-by-meta support for terms in line with post, comment, and
user queries.

As a byproduct of these improvements, $meta_key and $meta_value parameters
have been introduced to get_terms(). They interact with $meta_query in the
same way as in WP_Query and other query classes.

Props jadpm, eherman24.
Fixes #34996.

Location:
trunk
Files:
2 edited

Legend:

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

    r36400 r36485  
    10611061 *              Introduced the 'meta_query' and 'update_term_meta_cache' parameters. Converted to return
    10621062 *              a list of WP_Term objects.
     1063 * @since 4.5.0 Introduced 'meta_key' and 'meta_value' parameters. Introduced the ability to order results by metadata.
    10631064 *
    10641065 * @global wpdb  $wpdb WordPress database abstraction object.
     
    10721073 *                                                'term_group', 'term_id', 'id', 'description'), 'count' for term
    10731074 *                                                taxonomy count, 'include' to match the 'order' of the $include param,
    1074  *                                                or 'none' to skip ORDER BY. Defaults to 'name'.
     1075 *                                                'meta_value', 'meta_value_num', the value of `$meta_key`, the array
     1076 *                                                keys of `$meta_query`, or 'none' to omit the ORDER BY clause.
     1077 *                                                Defaults to 'name'.
    10751078 *     @type string       $order                  Whether to order terms in ascending or descending order.
    10761079 *                                                Accepts 'ASC' (ascending) or 'DESC' (descending).
     
    11201123 *     @type array        $meta_query             Meta query clauses to limit retrieved terms by.
    11211124 *                                                See `WP_Meta_Query`. Default empty.
     1125 *     @type string       $meta_key               Limit terms to those matching a specific metadata key. Can be used in
     1126 *                                                conjunction with `$meta_value`.
     1127 *     @type string       $meta_value             Limit terms to those matching a specific metadata value. Usually used
     1128 *                                                in conjunction with `$meta_key`.
    11221129 * }
    11231130 * @return array|int|WP_Error List of WP_Term instances and their children. Will return WP_Error, if any of $taxonomies
     
    14151422    $join = '';
    14161423    $distinct = '';
    1417     if ( ! empty( $args['meta_query'] ) ) {
    1418         $mquery = new WP_Meta_Query( $args['meta_query'] );
    1419         $mq_sql = $mquery->get_sql( 'term', 't', 'term_id' );
    1420 
     1424
     1425    $mquery = new WP_Meta_Query();
     1426    $mquery->parse_query_vars( $args );
     1427    $mq_sql = $mquery->get_sql( 'term', 't', 'term_id' );
     1428    $meta_clauses = $mquery->get_clauses();
     1429
     1430    if ( ! empty( $meta_clauses ) ) {
    14211431        $join  .= $mq_sql['join'];
    14221432        $where .= $mq_sql['where'];
    14231433        $distinct .= "DISTINCT";
     1434
     1435        // 'orderby' support.
     1436        $allowed_keys = array();
     1437        $primary_meta_key   = null;
     1438        $primary_meta_query = reset( $meta_clauses );
     1439        if ( ! empty( $primary_meta_query['key'] ) ) {
     1440            $primary_meta_key = $primary_meta_query['key'];
     1441            $allowed_keys[] = $primary_meta_key;
     1442        }
     1443        $allowed_keys[] = 'meta_value';
     1444        $allowed_keys[] = 'meta_value_num';
     1445        $allowed_keys   = array_merge( $allowed_keys, array_keys( $meta_clauses ) );
     1446
     1447        if ( ! empty( $args['orderby'] ) && in_array( $args['orderby'], $allowed_keys ) ) {
     1448            switch( $args['orderby'] ) {
     1449                case $primary_meta_key:
     1450                case 'meta_value':
     1451                    if ( ! empty( $primary_meta_query['type'] ) ) {
     1452                        $orderby = "ORDER BY CAST({$primary_meta_query['alias']}.meta_value AS {$primary_meta_query['cast']})";
     1453                    } else {
     1454                        $orderby = "ORDER BY {$primary_meta_query['alias']}.meta_value";
     1455                    }
     1456                    break;
     1457
     1458                case 'meta_value_num':
     1459                    $orderby = "ORDER BY {$primary_meta_query['alias']}.meta_value+0";
     1460                    break;
     1461
     1462                default:
     1463                    if ( array_key_exists( $args['orderby'], $meta_clauses ) ) {
     1464                        // $orderby corresponds to a meta_query clause.
     1465                        $meta_clause = $meta_clauses[ $args['orderby'] ];
     1466                        $orderby = "ORDER BY CAST({$meta_clause['alias']}.meta_value AS {$meta_clause['cast']})";
     1467                    }
     1468                    break;
     1469            }
     1470        }
    14241471    }
    14251472
  • trunk/tests/phpunit/tests/term/getTerms.php

    r36348 r36485  
    12341234    }
    12351235
     1236    /**
     1237     * @ticket 34996
     1238     */
     1239    public function test_orderby_meta_value() {
     1240        register_taxonomy( 'wptests_tax', 'post' );
     1241        $terms = self::factory()->term->create_many( 3, array( 'taxonomy' => 'wptests_tax' ) );
     1242        add_term_meta( $terms[0], 'foo', 'zzz' );
     1243        add_term_meta( $terms[0], 'fee', 'ber' );
     1244        add_term_meta( $terms[1], 'foo', 'aaa' );
     1245        add_term_meta( $terms[1], 'fee', 'ber' );
     1246        add_term_meta( $terms[2], 'foo', 'jjj' );
     1247        add_term_meta( $terms[2], 'fee', 'ber' );
     1248
     1249        // Matches the first meta query clause.
     1250        $found = get_terms( 'wptests_tax', array(
     1251            'hide_empty' => false,
     1252            'meta_query' => array(
     1253                'relation' => 'AND',
     1254                array(
     1255                    'key' => 'foo',
     1256                    'compare' => 'EXISTS',
     1257                ),
     1258                array(
     1259                    'key' => 'fee',
     1260                    'compare' => 'EXISTS',
     1261                ),
     1262            ),
     1263            'orderby' => 'meta_value',
     1264            'order' => 'ASC',
     1265            'fields' => 'ids',
     1266        ) );
     1267
     1268        $this->assertEqualSets( array( $terms[1], $terms[2], $terms[0] ), $found );
     1269    }
     1270
     1271    /**
     1272     * @ticket 34996
     1273     */
     1274    public function test_orderby_meta_value_num() {
     1275        register_taxonomy( 'wptests_tax', 'post' );
     1276        $terms = self::factory()->term->create_many( 3, array( 'taxonomy' => 'wptests_tax' ) );
     1277        add_term_meta( $terms[0], 'foo', '999' );
     1278        add_term_meta( $terms[0], 'fee', 'ber' );
     1279        add_term_meta( $terms[1], 'foo', '111' );
     1280        add_term_meta( $terms[1], 'fee', 'ber' );
     1281        add_term_meta( $terms[2], 'foo', '555' );
     1282        add_term_meta( $terms[2], 'fee', 'ber' );
     1283
     1284        // Matches the first meta query clause.
     1285        $found = get_terms( 'wptests_tax', array(
     1286            'hide_empty' => false,
     1287            'meta_query' => array(
     1288                'relation' => 'AND',
     1289                array(
     1290                    'key' => 'foo',
     1291                    'compare' => 'EXISTS',
     1292                ),
     1293                array(
     1294                    'key' => 'fee',
     1295                    'compare' => 'EXISTS',
     1296                ),
     1297            ),
     1298            'orderby' => 'meta_value_num',
     1299            'order' => 'ASC',
     1300            'fields' => 'ids',
     1301        ) );
     1302
     1303        $this->assertEqualSets( array( $terms[1], $terms[2], $terms[0] ), $found );
     1304    }
     1305
     1306    /**
     1307     * @ticket 34996
     1308     */
     1309    public function test_orderby_meta_value_with_meta_key() {
     1310        register_taxonomy( 'wptests_tax', 'post' );
     1311        $terms = self::factory()->term->create_many( 3, array( 'taxonomy' => 'wptests_tax' ) );
     1312        add_term_meta( $terms[0], 'foo', 'bar' );
     1313        add_term_meta( $terms[0], 'fee', 'zzz' );
     1314        add_term_meta( $terms[0], 'faa', 'jjj' );
     1315        add_term_meta( $terms[1], 'foo', 'bar' );
     1316        add_term_meta( $terms[1], 'fee', 'aaa' );
     1317        add_term_meta( $terms[1], 'faa', 'aaa' );
     1318        add_term_meta( $terms[2], 'foo', 'bar' );
     1319        add_term_meta( $terms[2], 'fee', 'jjj' );
     1320        add_term_meta( $terms[2], 'faa', 'zzz' );
     1321
     1322        $found = get_terms( 'wptests_tax', array(
     1323            'hide_empty' => false,
     1324            'meta_key' => 'fee',
     1325            'orderby' => 'meta_value',
     1326            'order' => 'ASC',
     1327            'fields' => 'ids',
     1328        ) );
     1329
     1330        $this->assertEqualSets( array( $terms[1], $terms[2], $terms[0] ), $found );
     1331
     1332        $found = get_terms( 'wptests_tax', array(
     1333            'hide_empty' => false,
     1334            'meta_query' => array(
     1335                array(
     1336                    'key' => 'foo',
     1337                    'compare' => 'EXISTS',
     1338                ),
     1339            ),
     1340            'meta_key' => 'fee',
     1341            'orderby' => 'meta_value',
     1342            'order' => 'ASC',
     1343            'fields' => 'ids',
     1344        ) );
     1345
     1346        $this->assertEqualSets( array( $terms[1], $terms[2], $terms[0] ), $found );
     1347
     1348        // Matches the first meta query clause.
     1349        $found = get_terms( 'wptests_tax', array(
     1350            'hide_empty' => false,
     1351            'meta_query' => array(
     1352                'relation' => 'AND',
     1353                array(
     1354                    'key' => 'foo',
     1355                    'compare' => 'EXISTS',
     1356                ),
     1357                array(
     1358                    'key' => 'fee',
     1359                    'compare' => 'EXISTS',
     1360                ),
     1361            ),
     1362            'meta_key' => 'fee',
     1363            'orderby' => 'meta_value',
     1364            'order' => 'ASC',
     1365            'fields' => 'ids',
     1366        ) );
     1367
     1368        $this->assertEqualSets( array( $terms[1], $terms[2], $terms[0] ), $found );
     1369
     1370        // Matches the meta query clause corresponding to the 'meta_key' param.
     1371        $found = get_terms( 'wptests_tax', array(
     1372            'hide_empty' => false,
     1373            'meta_query' => array(
     1374                'relation' => 'AND',
     1375                array(
     1376                    'key' => 'foo',
     1377                    'compare' => 'EXISTS',
     1378                ),
     1379                array(
     1380                    'key' => 'fee',
     1381                    'compare' => 'EXISTS',
     1382                ),
     1383            ),
     1384            'meta_key' => 'faa',
     1385            'orderby' => 'meta_value',
     1386            'order' => 'ASC',
     1387            'fields' => 'ids',
     1388        ) );
     1389
     1390        $this->assertEqualSets( array( $terms[1], $terms[0], $terms[2] ), $found );
     1391    }
     1392
     1393    /**
     1394     * @ticket 34996
     1395     */
     1396    public function test_orderby_meta_value_num_with_meta_key() {
     1397        register_taxonomy( 'wptests_tax', 'post' );
     1398        $terms = self::factory()->term->create_many( 3, array( 'taxonomy' => 'wptests_tax' ) );
     1399        add_term_meta( $terms[0], 'foo', 'bar' );
     1400        add_term_meta( $terms[0], 'fee', '999' );
     1401        add_term_meta( $terms[0], 'faa', '555' );
     1402        add_term_meta( $terms[1], 'foo', 'bar' );
     1403        add_term_meta( $terms[1], 'fee', '111' );
     1404        add_term_meta( $terms[1], 'faa', '111' );
     1405        add_term_meta( $terms[2], 'foo', 'bar' );
     1406        add_term_meta( $terms[2], 'fee', '555' );
     1407        add_term_meta( $terms[2], 'faa', '999' );
     1408
     1409        $found = get_terms( 'wptests_tax', array(
     1410            'hide_empty' => false,
     1411            'meta_key' => 'fee',
     1412            'orderby' => 'meta_value',
     1413            'order' => 'ASC',
     1414            'fields' => 'ids',
     1415        ) );
     1416
     1417        $this->assertEqualSets( array( $terms[1], $terms[2], $terms[0] ), $found );
     1418
     1419        $found = get_terms( 'wptests_tax', array(
     1420            'hide_empty' => false,
     1421            'meta_query' => array(
     1422                array(
     1423                    'key' => 'foo',
     1424                    'compare' => 'EXISTS',
     1425                ),
     1426            ),
     1427            'meta_key' => 'fee',
     1428            'orderby' => 'meta_value',
     1429            'order' => 'ASC',
     1430            'fields' => 'ids',
     1431        ) );
     1432
     1433        $this->assertEqualSets( array( $terms[1], $terms[2], $terms[0] ), $found );
     1434
     1435        $found = get_terms( 'wptests_tax', array(
     1436            'hide_empty' => false,
     1437            'meta_query' => array(
     1438                'relation' => 'AND',
     1439                array(
     1440                    'key' => 'foo',
     1441                    'compare' => 'EXISTS',
     1442                ),
     1443                array(
     1444                    'key' => 'fee',
     1445                    'compare' => 'EXISTS',
     1446                ),
     1447            ),
     1448            'meta_key' => 'fee',
     1449            'orderby' => 'meta_value',
     1450            'order' => 'ASC',
     1451            'fields' => 'ids',
     1452        ) );
     1453
     1454        $this->assertEqualSets( array( $terms[1], $terms[2], $terms[0] ), $found );
     1455
     1456        $found = get_terms( 'wptests_tax', array(
     1457            'hide_empty' => false,
     1458            'meta_query' => array(
     1459                'relation' => 'AND',
     1460                array(
     1461                    'key' => 'foo',
     1462                    'compare' => 'EXISTS',
     1463                ),
     1464                array(
     1465                    'key' => 'fee',
     1466                    'compare' => 'EXISTS',
     1467                ),
     1468            ),
     1469            'meta_key' => 'faa',
     1470            'orderby' => 'meta_value',
     1471            'order' => 'ASC',
     1472            'fields' => 'ids',
     1473        ) );
     1474
     1475        $this->assertEqualSets( array( $terms[1], $terms[0], $terms[2] ), $found );
     1476    }
     1477
     1478    /**
     1479     * @ticket 34996
     1480     */
     1481    public function test_orderby_clause_key() {
     1482        register_taxonomy( 'wptests_tax', 'post' );
     1483        $terms = self::factory()->term->create_many( 3, array( 'taxonomy' => 'wptests_tax' ) );
     1484        add_term_meta( $terms[0], 'foo', 'zzz' );
     1485        add_term_meta( $terms[0], 'fee', 'jjj' );
     1486        add_term_meta( $terms[1], 'foo', 'aaa' );
     1487        add_term_meta( $terms[1], 'fee', 'aaa' );
     1488        add_term_meta( $terms[2], 'foo', 'jjj' );
     1489        add_term_meta( $terms[2], 'fee', 'zzz' );
     1490
     1491        $found = get_terms( 'wptests_tax', array(
     1492            'hide_empty' => false,
     1493            'meta_query' => array(
     1494                'relation' => 'AND',
     1495                'foo_key' => array(
     1496                    'key' => 'foo',
     1497                    'compare' => 'EXISTS',
     1498                ),
     1499                'fee_key' => array(
     1500                    'key' => 'fee',
     1501                    'compare' => 'EXISTS',
     1502                ),
     1503            ),
     1504            'orderby' => 'foo_key',
     1505            'order' => 'ASC',
     1506            'fields' => 'ids',
     1507        ) );
     1508
     1509        $this->assertEqualSets( array( $terms[1], $terms[2], $terms[0] ), $found );
     1510
     1511        $found = get_terms( 'wptests_tax', array(
     1512            'hide_empty' => false,
     1513            'meta_query' => array(
     1514                'relation' => 'AND',
     1515                'foo_key' => array(
     1516                    'key' => 'foo',
     1517                    'compare' => 'EXISTS',
     1518                ),
     1519                'fee_key' => array(
     1520                    'key' => 'fee',
     1521                    'compare' => 'EXISTS',
     1522                ),
     1523            ),
     1524            'orderby' => 'fee_key',
     1525            'order' => 'ASC',
     1526            'fields' => 'ids',
     1527        ) );
     1528
     1529        $this->assertEqualSets( array( $terms[1], $terms[0], $terms[2] ), $found );
     1530
     1531        $expected = get_terms( 'wptests_tax', array(
     1532            'hide_empty' => false,
     1533            'meta_query' => array(
     1534                'relation' => 'AND',
     1535                'foo_key' => array(
     1536                    'key' => 'foo',
     1537                    'compare' => 'EXISTS',
     1538                ),
     1539                'fee_key' => array(
     1540                    'key' => 'fee',
     1541                    'compare' => 'EXISTS',
     1542                ),
     1543            ),
     1544            'fields' => 'ids',
     1545        ) );
     1546
     1547        $found = get_terms( 'wptests_tax', array(
     1548            'hide_empty' => false,
     1549            'meta_query' => array(
     1550                'relation' => 'AND',
     1551                'foo_key' => array(
     1552                    'key' => 'foo',
     1553                    'compare' => 'EXISTS',
     1554                ),
     1555                'fee_key' => array(
     1556                    'key' => 'fee',
     1557                    'compare' => 'EXISTS',
     1558                ),
     1559            ),
     1560            'orderby' => 'faa_key',
     1561            'fields' => 'ids',
     1562        ) );
     1563
     1564        $this->assertEqualSets( $expected, $found );
     1565    }
     1566
    12361567    public function test_hierarchical_false_with_parent() {
    12371568        $initial_terms = $this->create_hierarchical_terms();
Note: See TracChangeset for help on using the changeset viewer.