WordPress.org

Make WordPress Core

Ticket #37128: 37128.3.diff

File 37128.3.diff, 23.6 KB (added by swissspidy, 3 years ago)
  • new file src/wp-includes/class-wp-list-util.php

    diff --git src/wp-includes/class-wp-list-util.php src/wp-includes/class-wp-list-util.php
    new file mode 100644
    index 0000000..0820bb3
    - +  
     1<?php
     2/**
     3 * WordPress List utility class
     4 *
     5 * @package WordPress
     6 * @since 4.7.0
     7 */
     8
     9/**
     10 * List utility.
     11 *
     12 * Utility class to handle operations on an array of objects.
     13 *
     14 * @since 4.7.0
     15 */
     16class WP_List_Util {
     17        /**
     18         * The input array.
     19         *
     20         * @since 4.7.0
     21         * @access private
     22         * @var array
     23         */
     24        private $input = array();
     25
     26        /**
     27         * The output array.
     28         *
     29         * @since 4.7.0
     30         * @access private
     31         * @var array
     32         */
     33        private $output = array();
     34
     35        /**
     36         * Temporary arguments for sorting.
     37         *
     38         * @since 4.7.0
     39         * @access private
     40         * @var array
     41         */
     42        private $orderby = array();
     43
     44        /**
     45         * Constructor.
     46         *
     47         * Sets the input array.
     48         *
     49         * @since 4.7.0
     50         *
     51         * @param array $input Array to perform operations on.
     52         */
     53        public function __construct( $input ) {
     54                $this->output = $this->input = $input;
     55        }
     56
     57        /**
     58         * Returns the original input array.
     59         *
     60         * @since 4.7.0
     61         * @access public
     62         *
     63         * @return array The input array.
     64         */
     65        public function get_input() {
     66                return $this->input;
     67        }
     68
     69        /**
     70         * Returns the output array.
     71         *
     72         * @since 4.7.0
     73         * @access public
     74         *
     75         * @return array The output array.
     76         */
     77        public function get_output() {
     78                return $this->output;
     79        }
     80
     81        /**
     82         * Filters the list, based on a set of key => value arguments.
     83         *
     84         * @since 4.7.0
     85         *
     86         * @param array  $args     Optional. An array of key => value arguments to match
     87         *                         against each object. Default empty array.
     88         * @param string $operator Optional. The logical operation to perform. 'AND' means
     89         *                         all elements from the array must match. 'OR' means only
     90         *                         one element needs to match. 'NOT' means no elements may
     91         *                         match. Default 'AND'.
     92         * @return array Array of found values.
     93         */
     94        public function filter( $args = array(), $operator = 'AND' ) {
     95                if ( empty( $args ) ) {
     96                        return $this->output;
     97                }
     98
     99                $operator = strtoupper( $operator );
     100
     101                if ( ! in_array( $operator, array( 'AND', 'OR', 'NOT' ), true ) ) {
     102                        return array();
     103                }
     104
     105                $count = count( $args );
     106                $filtered = array();
     107
     108                foreach ( $this->output as $key => $obj ) {
     109                        $to_match = (array) $obj;
     110
     111                        $matched = 0;
     112                        foreach ( $args as $m_key => $m_value ) {
     113                                if ( array_key_exists( $m_key, $to_match ) && $m_value == $to_match[ $m_key ] ) {
     114                                        $matched++;
     115                                }
     116                        }
     117
     118                        if ( ( 'AND' == $operator && $matched == $count )
     119                          || ( 'OR' == $operator && $matched > 0 )
     120                          || ( 'NOT' == $operator && 0 == $matched ) ) {
     121                                $filtered[$key] = $obj;
     122                        }
     123                }
     124
     125                $this->output = $filtered;
     126
     127                return $this->output;
     128        }
     129
     130        /**
     131         * Plucks a certain field out of each object in the list.
     132         *
     133         * This has the same functionality and prototype of
     134         * array_column() (PHP 5.5) but also supports objects.
     135         *
     136         * @since 4.7.0
     137         *
     138         * @param int|string $field     Field from the object to place instead of the entire object
     139         * @param int|string $index_key Optional. Field from the object to use as keys for the new array.
     140         *                              Default null.
     141         * @return array Array of found values. If `$index_key` is set, an array of found values with keys
     142         *               corresponding to `$index_key`. If `$index_key` is null, array keys from the original
     143         *               `$list` will be preserved in the results.
     144         */
     145        public function pluck( $field, $index_key = null ) {
     146                if ( ! $index_key ) {
     147                        /*
     148                         * This is simple. Could at some point wrap array_column()
     149                         * if we knew we had an array of arrays.
     150                         */
     151                        foreach ( $this->output as $key => $value ) {
     152                                if ( is_object( $value ) ) {
     153                                        $this->output[ $key ] = $value->$field;
     154                                } else {
     155                                        $this->output[ $key ] = $value[ $field ];
     156                                }
     157                        }
     158                        return $this->output;
     159                }
     160
     161                /*
     162                 * When index_key is not set for a particular item, push the value
     163                 * to the end of the stack. This is how array_column() behaves.
     164                 */
     165                $newlist = array();
     166                foreach ( $this->output as $value ) {
     167                        if ( is_object( $value ) ) {
     168                                if ( isset( $value->$index_key ) ) {
     169                                        $newlist[ $value->$index_key ] = $value->$field;
     170                                } else {
     171                                        $newlist[] = $value->$field;
     172                                }
     173                        } else {
     174                                if ( isset( $value[ $index_key ] ) ) {
     175                                        $newlist[ $value[ $index_key ] ] = $value[ $field ];
     176                                } else {
     177                                        $newlist[] = $value[ $field ];
     178                                }
     179                        }
     180                }
     181
     182                $this->output = $newlist;
     183
     184                return $this->output;
     185        }
     186
     187        /**
     188         * Sorts the list, based on one or more orderby arguments.
     189         *
     190         * @since 4.7.0
     191         *
     192         * @param string|array $orderby Optional. Either the field name to order by or an array
     193         *                              of multiple orderby fields as $orderby => $order.
     194         * @param string       $order   Optional. Either 'ASC' or 'DESC'. Only used if $orderby
     195         *                              is a string.
     196         * @return array The sorted array.
     197         */
     198        public function sort( $orderby = array(), $order = 'ASC' ) {
     199                if ( empty( $orderby ) ) {
     200                        return $this->output;
     201                }
     202
     203                if ( is_string( $orderby ) ) {
     204                        $orderby = array( $orderby => $order );
     205                }
     206
     207                foreach ( $orderby as $field => $direction ) {
     208                        $orderby[ $field ] = 'DESC' === strtoupper( $direction ) ? 'DESC' : 'ASC';
     209                }
     210
     211                $this->orderby = $orderby;
     212
     213                usort( $this->output, array( $this, 'sort_callback' ) );
     214
     215                $this->orderby = array();
     216
     217                return $this->output;
     218        }
     219
     220        /**
     221         * Callback to sort the list by specific fields.
     222         *
     223         * @since 4.7.0
     224         * @access private
     225         *
     226         * @see WP_List_Util::sort()
     227         *
     228         * @param object|array $a One object to compare.
     229         * @param object|array $b The other object to compare.
     230         * @return int 0 if both objects equal. -1 if second object should come first, 1 otherwise.
     231         */
     232        private function sort_callback( $a, $b ) {
     233                if ( empty( $this->orderby ) ) {
     234                        return 0;
     235                }
     236
     237                $a = (array) $a;
     238                $b = (array) $b;
     239
     240                foreach ( $this->orderby as $field => $direction ) {
     241                        if ( ! isset( $a[ $field ] ) || ! isset( $b[ $field ] ) ) {
     242                                continue;
     243                        }
     244
     245                        if ( $a[ $field ] == $b[ $field ] ) {
     246                                continue;
     247                        }
     248
     249                        $results = 'DESC' === $direction ? array( 1, -1 ) : array( -1, 1 );
     250
     251                        if ( is_numeric( $a[ $field ] ) && is_numeric( $b[ $field ] ) ) {
     252                                return ( $a[ $field ] < $b[ $field ] ) ? $results[0] : $results[1];
     253                        }
     254
     255                        return 0 > strcmp( $a[ $field ], $b[ $field ] ) ? $results[0] : $results[1];
     256                }
     257
     258                return 0;
     259        }
     260}
  • src/wp-includes/functions.php

    diff --git src/wp-includes/functions.php src/wp-includes/functions.php
    index fa7e725..020f69a 100644
    function wp_is_numeric_array( $data ) { 
    34443444 * Filters a list of objects, based on a set of key => value arguments.
    34453445 *
    34463446 * @since 3.0.0
     3447 * @since 4.7.0 Uses WP_List_Util class.
    34473448 *
    34483449 * @param array       $list     An array of objects to filter
    34493450 * @param array       $args     Optional. An array of key => value arguments to match
    function wp_is_numeric_array( $data ) { 
    34573458 * @return array A list of objects or object fields.
    34583459 */
    34593460function wp_filter_object_list( $list, $args = array(), $operator = 'and', $field = false ) {
    3460         if ( ! is_array( $list ) )
     3461        if ( ! is_array( $list ) ) {
    34613462                return array();
     3463        }
     3464
     3465        $util = new WP_List_Util( $list );
    34623466
    3463         $list = wp_list_filter( $list, $args, $operator );
     3467        $util->filter( $args, $operator );
    34643468
    3465         if ( $field )
    3466                 $list = wp_list_pluck( $list, $field );
     3469        if ( $field ) {
     3470                $util->pluck( $field );
     3471        }
    34673472
    3468         return $list;
     3473        return $util->get_output();
    34693474}
    34703475
    34713476/**
    34723477 * Filters a list of objects, based on a set of key => value arguments.
    34733478 *
    34743479 * @since 3.1.0
     3480 * @since 4.7.0 Uses WP_List_Util class.
    34753481 *
    34763482 * @param array  $list     An array of objects to filter.
    34773483 * @param array  $args     Optional. An array of key => value arguments to match
    function wp_filter_object_list( $list, $args = array(), $operator = 'and', $fiel 
    34833489 * @return array Array of found values.
    34843490 */
    34853491function wp_list_filter( $list, $args = array(), $operator = 'AND' ) {
    3486         if ( ! is_array( $list ) )
     3492        if ( ! is_array( $list ) ) {
    34873493                return array();
    3488 
    3489         if ( empty( $args ) )
    3490                 return $list;
    3491 
    3492         $operator = strtoupper( $operator );
    3493         $count = count( $args );
    3494         $filtered = array();
    3495 
    3496         foreach ( $list as $key => $obj ) {
    3497                 $to_match = (array) $obj;
    3498 
    3499                 $matched = 0;
    3500                 foreach ( $args as $m_key => $m_value ) {
    3501                         if ( array_key_exists( $m_key, $to_match ) && $m_value == $to_match[ $m_key ] )
    3502                                 $matched++;
    3503                 }
    3504 
    3505                 if ( ( 'AND' == $operator && $matched == $count )
    3506                   || ( 'OR' == $operator && $matched > 0 )
    3507                   || ( 'NOT' == $operator && 0 == $matched ) ) {
    3508                         $filtered[$key] = $obj;
    3509                 }
    35103494        }
    35113495
    3512         return $filtered;
     3496        $util = new WP_List_Util( $list );
     3497        return $util->filter( $args, $operator );
    35133498}
    35143499
    35153500/**
    function wp_list_filter( $list, $args = array(), $operator = 'AND' ) { 
    35203505 *
    35213506 * @since 3.1.0
    35223507 * @since 4.0.0 $index_key parameter added.
     3508 * @since 4.7.0 Uses WP_List_Util class.
    35233509 *
    35243510 * @param array      $list      List of objects or arrays
    35253511 * @param int|string $field     Field from the object to place instead of the entire object
    function wp_list_filter( $list, $args = array(), $operator = 'AND' ) { 
    35303516 *               `$list` will be preserved in the results.
    35313517 */
    35323518function wp_list_pluck( $list, $field, $index_key = null ) {
    3533         if ( ! $index_key ) {
    3534                 /*
    3535                  * This is simple. Could at some point wrap array_column()
    3536                  * if we knew we had an array of arrays.
    3537                  */
    3538                 foreach ( $list as $key => $value ) {
    3539                         if ( is_object( $value ) ) {
    3540                                 $list[ $key ] = $value->$field;
    3541                         } else {
    3542                                 $list[ $key ] = $value[ $field ];
    3543                         }
    3544                 }
    3545                 return $list;
    3546         }
     3519        $util = new WP_List_Util( $list );
     3520        return $util->pluck( $field, $index_key );
     3521}
    35473522
    3548         /*
    3549          * When index_key is not set for a particular item, push the value
    3550          * to the end of the stack. This is how array_column() behaves.
    3551          */
    3552         $newlist = array();
    3553         foreach ( $list as $value ) {
    3554                 if ( is_object( $value ) ) {
    3555                         if ( isset( $value->$index_key ) ) {
    3556                                 $newlist[ $value->$index_key ] = $value->$field;
    3557                         } else {
    3558                                 $newlist[] = $value->$field;
    3559                         }
    3560                 } else {
    3561                         if ( isset( $value[ $index_key ] ) ) {
    3562                                 $newlist[ $value[ $index_key ] ] = $value[ $field ];
    3563                         } else {
    3564                                 $newlist[] = $value[ $field ];
    3565                         }
    3566                 }
     3523/**
     3524 * Sorts a list of objects, based on one or more orderby arguments.
     3525 *
     3526 * @since 4.7.0
     3527 *
     3528 * @param array        $list    An array of objects to filter.
     3529 * @param string|array $orderby Optional. Either the field name to order by or an array
     3530 *                              of multiple orderby fields as $orderby => $order.
     3531 * @param string       $order   Optional. Either 'ASC' or 'DESC'. Only used if $orderby
     3532 *                              is a string.
     3533 * @return array The sorted array.
     3534 */
     3535function wp_list_sort( $list, $orderby = array(), $order = 'ASC' ) {
     3536        if ( ! is_array( $list ) ) {
     3537                return array();
    35673538        }
    35683539
    3569         return $newlist;
     3540        $util = new WP_List_Util( $list );
     3541        return $util->sort( $orderby, $order );
    35703542}
    35713543
    35723544/**
  • src/wp-settings.php

    diff --git src/wp-settings.php src/wp-settings.php
    index 4a03e0a..a3bdfd7 100644
    wp_set_lang_dir(); 
    9191
    9292// Load early WordPress files.
    9393require( ABSPATH . WPINC . '/compat.php' );
     94require( ABSPATH . WPINC . '/class-wp-list-util.php' );
    9495require( ABSPATH . WPINC . '/functions.php' );
    9596require( ABSPATH . WPINC . '/class-wp.php' );
    9697require( ABSPATH . WPINC . '/class-wp-error.php' );
  • new file tests/phpunit/tests/functions/wpListUtil.php

    diff --git tests/phpunit/tests/functions/wpListUtil.php tests/phpunit/tests/functions/wpListUtil.php
    new file mode 100644
    index 0000000..ca20b06
    - +  
     1<?php
     2
     3/**
     4 * @group functions.php
     5 */
     6class Tests_WP_List_Util extends WP_UnitTestCase {
     7        public function data_test_wp_list_pluck() {
     8                return array(
     9                        'arrays'                         => array(
     10                                array(
     11                                        array( 'foo' => 'bar', 'bar' => 'baz', 'abc' => 'xyz' ),
     12                                        array( 'foo' => 'foo', '123' => '456', 'lorem' => 'ipsum' ),
     13                                        array( 'foo' => 'baz' ),
     14                                ),
     15                                'foo',
     16                                null,
     17                                array( 'bar', 'foo', 'baz' ),
     18                        ),
     19                        'arrays with index key'          => array(
     20                                array(
     21                                        array( 'foo' => 'bar', 'bar' => 'baz', 'abc' => 'xyz', 'key' => 'foo' ),
     22                                        array( 'foo' => 'foo', '123' => '456', 'lorem' => 'ipsum', 'key' => 'bar' ),
     23                                        array( 'foo' => 'baz', 'key' => 'value' ),
     24                                ),
     25                                'foo',
     26                                'key',
     27                                array( 'foo' => 'bar', 'bar' => 'foo', 'value' => 'baz' ),
     28                        ),
     29                        'arrays with index key missing'  => array(
     30                                array(
     31                                        array( 'foo' => 'bar', 'bar' => 'baz', 'abc' => 'xyz' ),
     32                                        array( 'foo' => 'foo', '123' => '456', 'lorem' => 'ipsum', 'key' => 'bar' ),
     33                                        array( 'foo' => 'baz', 'key' => 'value' ),
     34                                ),
     35                                'foo',
     36                                'key',
     37                                array( 'bar' => 'foo', 'value' => 'baz', 'bar' ),
     38                        ),
     39                        'objects'                        => array(
     40                                array(
     41                                        (object) array( 'foo' => 'bar', 'bar' => 'baz', 'abc' => 'xyz' ),
     42                                        (object) array( 'foo' => 'foo', '123' => '456', 'lorem' => 'ipsum' ),
     43                                        (object) array( 'foo' => 'baz' ),
     44                                ),
     45                                'foo',
     46                                null,
     47                                array( 'bar', 'foo', 'baz' ),
     48                        ),
     49                        'objects with index key'         => array(
     50                                array(
     51                                        (object) array( 'foo' => 'bar', 'bar' => 'baz', 'abc' => 'xyz', 'key' => 'foo' ),
     52                                        (object) array( 'foo' => 'foo', '123' => '456', 'lorem' => 'ipsum', 'key' => 'bar' ),
     53                                        (object) array( 'foo' => 'baz', 'key' => 'value' ),
     54                                ),
     55                                'foo',
     56                                'key',
     57                                array( 'foo' => 'bar', 'bar' => 'foo', 'value' => 'baz' ),
     58                        ),
     59                        'objects with index key missing' => array(
     60                                array(
     61                                        (object) array( 'foo' => 'bar', 'bar' => 'baz', 'abc' => 'xyz' ),
     62                                        (object) array( 'foo' => 'foo', '123' => '456', 'lorem' => 'ipsum', 'key' => 'bar' ),
     63                                        (object) array( 'foo' => 'baz', 'key' => 'value' ),
     64                                ),
     65                                'foo',
     66                                'key',
     67                                array( 'bar' => 'foo', 'value' => 'baz', 'bar' ),
     68                        ),
     69                );
     70        }
     71
     72        /**
     73         * @dataProvider data_test_wp_list_pluck
     74         *
     75         * @param array      $list      List of objects or arrays.
     76         * @param int|string $field     Field from the object to place instead of the entire object
     77         * @param int|string $index_key Field from the object to use as keys for the new array.
     78         * @param array      $expected  Expected result.
     79         */
     80        public function test_wp_list_pluck( $list, $field, $index_key, $expected ) {
     81                $this->assertEqualSetsWithIndex( $expected, wp_list_pluck( $list, $field, $index_key ) );
     82        }
     83
     84        public function data_test_wp_list_filter() {
     85                return array(
     86                        'string instead of array'  => array(
     87                                'foo',
     88                                array(),
     89                                'AND',
     90                                array(),
     91                        ),
     92                        'object instead of array'  => array(
     93                                (object) array( 'foo' ),
     94                                array(),
     95                                'AND',
     96                                array(),
     97                        ),
     98                        'empty args'               => array(
     99                                array( 'foo', 'bar' ),
     100                                array(),
     101                                'AND',
     102                                array( 'foo', 'bar' ),
     103                        ),
     104                        'invalid operator'         => array(
     105                                array(
     106                                        (object) array( 'foo' => 'bar' ),
     107                                        (object) array( 'foo' => 'baz' ),
     108                                ),
     109                                array( 'foo' => 'bar' ),
     110                                'XOR',
     111                                array(),
     112                        ),
     113                        'single argument to match' => array(
     114                                array(
     115                                        (object) array( 'foo' => 'bar', 'bar' => 'baz', 'abc' => 'xyz', 'key' => 'foo' ),
     116                                        (object) array( 'foo' => 'foo', '123' => '456', 'lorem' => 'ipsum', 'key' => 'bar' ),
     117                                        (object) array( 'foo' => 'baz', 'key' => 'value' ),
     118                                        (object) array( 'foo' => 'bar', 'key' => 'value' ),
     119                                ),
     120                                array( 'foo' => 'bar' ),
     121                                'AND',
     122                                array(
     123                                        0 => (object) array( 'foo' => 'bar', 'bar' => 'baz', 'abc' => 'xyz', 'key' => 'foo' ),
     124                                        3 => (object) array( 'foo' => 'bar', 'key' => 'value' ),
     125                                ),
     126                        ),
     127                        'all must match'           => array(
     128                                array(
     129                                        (object) array( 'foo' => 'bar', 'bar' => 'baz', 'abc' => 'xyz', 'key' => 'foo' ),
     130                                        (object) array( 'foo' => 'foo', '123' => '456', 'lorem' => 'ipsum', 'key' => 'bar' ),
     131                                        (object) array( 'foo' => 'baz', 'key' => 'value', 'bar' => 'baz' ),
     132                                        (object) array( 'foo' => 'bar', 'key' => 'value' ),
     133                                ),
     134                                array( 'foo' => 'bar', 'bar' => 'baz' ),
     135                                'AND',
     136                                array(
     137                                        0 => (object) array( 'foo' => 'bar', 'bar' => 'baz', 'abc' => 'xyz', 'key' => 'foo' ),
     138                                ),
     139                        ),
     140                        'any must match'           => array(
     141                                array(
     142                                        (object) array( 'foo' => 'bar', 'bar' => 'baz', 'abc' => 'xyz', 'key' => 'foo' ),
     143                                        (object) array( 'foo' => 'foo', '123' => '456', 'lorem' => 'ipsum', 'key' => 'bar' ),
     144                                        (object) array( 'foo' => 'baz', 'key' => 'value', 'bar' => 'baz' ),
     145                                        (object) array( 'foo' => 'bar', 'key' => 'value' ),
     146                                ),
     147                                array( 'key' => 'value', 'bar' => 'baz' ),
     148                                'OR',
     149                                array(
     150                                        0 => (object) array( 'foo' => 'bar', 'bar' => 'baz', 'abc' => 'xyz', 'key' => 'foo' ),
     151                                        2 => (object) array( 'foo' => 'baz', 'key' => 'value', 'bar' => 'baz' ),
     152                                        3 => (object) array( 'foo' => 'bar', 'key' => 'value' ),
     153                                ),
     154                        ),
     155                        'none must match'          => array(
     156                                array(
     157                                        (object) array( 'foo' => 'bar', 'bar' => 'baz', 'abc' => 'xyz', 'key' => 'foo' ),
     158                                        (object) array( 'foo' => 'foo', '123' => '456', 'lorem' => 'ipsum', 'key' => 'bar' ),
     159                                        (object) array( 'foo' => 'baz', 'key' => 'value' ),
     160                                        (object) array( 'foo' => 'bar', 'key' => 'value' ),
     161                                ),
     162                                array( 'key' => 'value', 'bar' => 'baz' ),
     163                                'NOT',
     164                                array(
     165                                        1 => (object) array( 'foo' => 'foo', '123' => '456', 'lorem' => 'ipsum', 'key' => 'bar' ),
     166                                ),
     167                        ),
     168                );
     169        }
     170
     171        /**
     172         * @dataProvider data_test_wp_list_filter
     173         *
     174         * @param array  $list     An array of objects to filter.
     175         * @param array  $args     An array of key => value arguments to match
     176         *                         against each object.
     177         * @param string $operator The logical operation to perform.
     178         * @param array  $expected Expected result.
     179         */
     180        public function test_wp_list_filter( $list, $args, $operator, $expected ) {
     181                $this->assertEqualSetsWithIndex( $expected, wp_list_filter( $list, $args, $operator ) );
     182        }
     183
     184        public function data_test_wp_list_sort() {
     185                return array(
     186                        'single orderby ascending'        => array(
     187                                array(
     188                                        array( 'foo' => 'bar', 'bar' => 'baz', 'key' => 'foo' ),
     189                                        array( 'foo' => 'foo', 'lorem' => 'ipsum', 'key' => 'bar' ),
     190                                        array( 'foo' => 'baz', 'key' => 'value' ),
     191                                        array( 'foo' => 'bar', 'key' => 'value' ),
     192                                ),
     193                                'foo',
     194                                'ASC',
     195                                array(
     196                                        array( 'foo' => 'bar', 'bar' => 'baz', 'key' => 'foo' ),
     197                                        array( 'foo' => 'bar', 'key' => 'value' ),
     198                                        array( 'foo' => 'baz', 'key' => 'value' ),
     199                                        array( 'foo' => 'foo', 'lorem' => 'ipsum', 'key' => 'bar' ),
     200                                ),
     201                        ),
     202                        'single orderby descending'       => array(
     203                                array(
     204                                        array( 'foo' => 'bar', 'bar' => 'baz', 'key' => 'foo' ),
     205                                        array( 'foo' => 'foo', 'lorem' => 'ipsum', 'key' => 'bar' ),
     206                                        array( 'foo' => 'baz', 'key' => 'value' ),
     207                                        array( 'foo' => 'bar', 'key' => 'value' ),
     208                                ),
     209                                'foo',
     210                                'DESC',
     211                                array(
     212                                        array( 'foo' => 'foo', 'lorem' => 'ipsum', 'key' => 'bar' ),
     213                                        array( 'foo' => 'baz', 'key' => 'value' ),
     214                                        array( 'foo' => 'bar', 'bar' => 'baz', 'key' => 'foo' ),
     215                                        array( 'foo' => 'bar', 'key' => 'value' ),
     216                                ),
     217                        ),
     218                        'single orderby array ascending'  => array(
     219                                array(
     220                                        array( 'foo' => 'bar', 'bar' => 'baz', 'key' => 'foo' ),
     221                                        array( 'foo' => 'foo', 'lorem' => 'ipsum', 'key' => 'bar' ),
     222                                        array( 'foo' => 'baz', 'key' => 'value' ),
     223                                        array( 'foo' => 'bar', 'key' => 'value' ),
     224                                ),
     225                                array( 'foo' => 'ASC' ),
     226                                'IGNORED',
     227                                array(
     228                                        array( 'foo' => 'bar', 'bar' => 'baz', 'key' => 'foo' ),
     229                                        array( 'foo' => 'bar', 'key' => 'value' ),
     230                                        array( 'foo' => 'baz', 'key' => 'value' ),
     231                                        array( 'foo' => 'foo', 'lorem' => 'ipsum', 'key' => 'bar' ),
     232                                ),
     233                        ),
     234                        'single orderby array descending' => array(
     235                                array(
     236                                        array( 'foo' => 'bar', 'bar' => 'baz', 'key' => 'foo' ),
     237                                        array( 'foo' => 'foo', 'lorem' => 'ipsum', 'key' => 'bar' ),
     238                                        array( 'foo' => 'baz', 'key' => 'value' ),
     239                                        array( 'foo' => 'bar', 'key' => 'value' ),
     240                                ),
     241                                array( 'foo' => 'DESC' ),
     242                                'IGNORED',
     243                                array(
     244                                        array( 'foo' => 'foo', 'lorem' => 'ipsum', 'key' => 'bar' ),
     245                                        array( 'foo' => 'baz', 'key' => 'value' ),
     246                                        array( 'foo' => 'bar', 'bar' => 'baz', 'key' => 'foo' ),
     247                                        array( 'foo' => 'bar', 'key' => 'value' ),
     248                                ),
     249                        ),
     250                        'multiple orderby ascending'      => array(
     251                                array(
     252                                        array( 'foo' => 'bar', 'bar' => 'baz', 'key' => 'foo' ),
     253                                        array( 'foo' => 'foo', 'lorem' => 'ipsum', 'key' => 'bar' ),
     254                                        array( 'foo' => 'foo', 'key' => 'key' ),
     255                                        array( 'foo' => 'baz', 'key' => 'key' ),
     256                                        array( 'foo' => 'bar', 'key' => 'value' ),
     257                                ),
     258                                array( 'key' => 'ASC', 'foo' => 'ASC' ),
     259                                'IGNORED',
     260                                array(
     261                                        array( 'foo' => 'foo', 'lorem' => 'ipsum', 'key' => 'bar' ),
     262                                        array( 'foo' => 'bar', 'bar' => 'baz', 'key' => 'foo' ),
     263                                        array( 'foo' => 'baz', 'key' => 'key' ),
     264                                        array( 'foo' => 'foo', 'key' => 'key' ),
     265                                        array( 'foo' => 'bar', 'key' => 'value' ),
     266                                ),
     267                        ),
     268                        'multiple orderby descending'     => array(
     269                                array(
     270                                        array( 'foo' => 'bar', 'bar' => 'baz', 'key' => 'foo' ),
     271                                        array( 'foo' => 'foo', 'lorem' => 'ipsum', 'key' => 'bar' ),
     272                                        array( 'foo' => 'foo', 'key' => 'key' ),
     273                                        array( 'foo' => 'baz', 'key' => 'key' ),
     274                                        array( 'foo' => 'bar', 'key' => 'value' ),
     275                                ),
     276                                array( 'key' => 'DESC', 'foo' => 'DESC' ),
     277                                'IGNORED',
     278                                array(
     279                                        array( 'foo' => 'bar', 'key' => 'value' ),
     280                                        array( 'foo' => 'foo', 'key' => 'key' ),
     281                                        array( 'foo' => 'baz', 'key' => 'key' ),
     282                                        array( 'foo' => 'bar', 'bar' => 'baz', 'key' => 'foo' ),
     283                                        array( 'foo' => 'foo', 'lorem' => 'ipsum', 'key' => 'bar' ),
     284                                ),
     285                        ),
     286                        'multiple orderby mixed'          => array(
     287                                array(
     288                                        array( 'foo' => 'bar', 'bar' => 'baz', 'key' => 'foo' ),
     289                                        array( 'foo' => 'foo', 'lorem' => 'ipsum', 'key' => 'bar' ),
     290                                        array( 'foo' => 'foo', 'key' => 'key' ),
     291                                        array( 'foo' => 'baz', 'key' => 'key' ),
     292                                        array( 'foo' => 'bar', 'key' => 'value' ),
     293                                ),
     294                                array( 'key' => 'DESC', 'foo' => 'ASC' ),
     295                                'IGNORED',
     296                                array(
     297                                        array( 'foo' => 'bar', 'key' => 'value' ),
     298                                        array( 'foo' => 'baz', 'key' => 'key' ),
     299                                        array( 'foo' => 'foo', 'key' => 'key' ),
     300                                        array( 'foo' => 'bar', 'bar' => 'baz', 'key' => 'foo' ),
     301                                        array( 'foo' => 'foo', 'lorem' => 'ipsum', 'key' => 'bar' ),
     302                                ),
     303                        ),
     304                );
     305        }
     306
     307        /**
     308         * @dataProvider data_test_wp_list_sort
     309         *
     310         * @param string|array $orderby Either the field name to order by or an array
     311         *                              of multiple orderby fields as $orderby => $order.
     312         * @param string       $order   Either 'ASC' or 'DESC'.
     313         */
     314        public function test_wp_list_sort( $list, $orderby, $order, $expected ) {
     315                $this->assertEquals( $expected, wp_list_sort( $list, $orderby, $order ) );
     316        }
     317
     318        public function test_wp_list_util_get_input() {
     319                $input = array( 'foo', 'bar' );
     320                $util  = new WP_List_Util( $input );
     321
     322                $this->assertEqualSets( $input, $util->get_input() );
     323        }
     324
     325        public function test_wp_list_util_get_output_immediately() {
     326                $input = array( 'foo', 'bar' );
     327                $util  = new WP_List_Util( $input );
     328
     329                $this->assertEqualSets( $input, $util->get_output() );
     330        }
     331
     332        public function test_wp_list_util_get_output() {
     333                $expected = array( (object) array( 'foo' => 'bar', 'bar' => 'baz' ) );
     334
     335                $util   = new WP_List_Util( array( (object) array( 'foo' => 'bar', 'bar' => 'baz' ), (object) array( 'bar' => 'baz' ) ) );
     336                $actual = $util->filter( array( 'foo' => 'bar' ) );
     337
     338                $this->assertEqualSets( $expected, $actual );
     339                $this->assertEqualSets( $expected, $util->get_output() );
     340        }
     341}