WordPress.org

Make WordPress Core

Changeset 29027


Ignore:
Timestamp:
07/08/14 17:15:53 (3 years ago)
Author:
wonderboymusic
Message:

Allow an array() to be passed as the value for orderby to WP_Query. Allows for an independent order value for each key.

Example: 'orderby' => array( 'title' => 'DESC', 'menu_order' => 'ASC' ).

Adds docs and unit tests.

Props wonderboymusic, johnbillion, DrewAPicture, dd32, andy.
See #17065.

Location:
trunk
Files:
2 edited

Legend:

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

    r28987 r29027  
    22012201 
    22022202    /** 
     2203     * If the passed orderby value is allowed, convert the alias to a 
     2204     * properly-prefixed orderby value. 
     2205     * 
     2206     * @since 4.0.0 
     2207     * @access protected 
     2208     * 
     2209     * @global wpdb $wpdb WordPress database access abstraction object. 
     2210     * 
     2211     * @param string $orderby Alias for the field to order by. 
     2212     * @return string|bool Table-prefixed value to used in the ORDER clause. False otherwise. 
     2213     */ 
     2214    protected function parse_orderby( $orderby ) { 
     2215        global $wpdb; 
     2216 
     2217        // Used to filter values. 
     2218        $allowed_keys = array( 
     2219            'post_name', 'post_author', 'post_date', 'post_title', 'post_modified', 
     2220            'post_parent', 'post_type', 'name', 'author', 'date', 'title', 'modified', 
     2221            'parent', 'type', 'ID', 'menu_order', 'comment_count', 'rand', 
     2222        ); 
     2223 
     2224        $meta_key = $this->get( 'meta_key' ); 
     2225        if ( ! empty( $meta_key ) ) { 
     2226            $allowed_keys[] = $meta_key; 
     2227            $allowed_keys[] = 'meta_value'; 
     2228            $allowed_keys[] = 'meta_value_num'; 
     2229        } 
     2230 
     2231        if ( ! in_array( $orderby, $allowed_keys ) ) { 
     2232            return false; 
     2233        } 
     2234 
     2235        switch ( $orderby ) { 
     2236            case 'post_name': 
     2237            case 'post_author': 
     2238            case 'post_date': 
     2239            case 'post_title': 
     2240            case 'post_modified': 
     2241            case 'post_parent': 
     2242            case 'post_type': 
     2243            case 'ID': 
     2244            case 'menu_order': 
     2245            case 'comment_count': 
     2246                $orderby = "$wpdb->posts.{$orderby}"; 
     2247                break; 
     2248            case 'rand': 
     2249                $orderby = 'RAND()'; 
     2250                break; 
     2251            case $meta_key: 
     2252            case 'meta_value': 
     2253                $type = $this->get( 'meta_type' ); 
     2254                if ( ! empty( $type ) ) { 
     2255                    $meta_type = $this->meta_query->get_cast_for_type( $type ); 
     2256                    $orderby = "CAST($wpdb->postmeta.meta_value AS {$meta_type})"; 
     2257                } else { 
     2258                    $orderby = "$wpdb->postmeta.meta_value"; 
     2259                } 
     2260                break; 
     2261            case 'meta_value_num': 
     2262                $orderby = "$wpdb->postmeta.meta_value+0"; 
     2263                break; 
     2264            default: 
     2265                $orderby = "$wpdb->posts.post_" . $orderby; 
     2266                break; 
     2267        } 
     2268 
     2269        return $orderby; 
     2270    } 
     2271 
     2272    /** 
     2273     * Parse an 'order' query variable and cast it to ASC or DESC as necessary. 
     2274     * 
     2275     * @since 4.0.0 
     2276     * @access protected 
     2277     * 
     2278     * @param string $order The 'order' query variable. 
     2279     * @return string The sanitized 'order' query variable. 
     2280     */ 
     2281    protected function parse_order( $order ) { 
     2282        if ( ! is_string( $order ) || empty( $order ) ) { 
     2283            return 'DESC'; 
     2284        } 
     2285 
     2286        if ( 'ASC' === strtoupper( $order ) ) { 
     2287            return 'ASC'; 
     2288        } else { 
     2289            return 'DESC'; 
     2290        } 
     2291    } 
     2292 
     2293    /** 
    22032294     * Sets the 404 property and saves whether query is feed. 
    22042295     * 
     
    27032794        $where .= $search . $whichauthor . $whichmimetype; 
    27042795 
    2705         if ( empty($q['order']) || ((strtoupper($q['order']) != 'ASC') && (strtoupper($q['order']) != 'DESC')) ) 
     2796        if ( ! isset( $q['order'] ) ) { 
    27062797            $q['order'] = 'DESC'; 
    2707  
    2708         // Order by 
    2709         if ( empty($q['orderby']) ) { 
    2710             $orderby = "$wpdb->posts.post_date " . $q['order']; 
     2798        } else { 
     2799            $q['order'] = $this->parse_order( $q['order'] ); 
     2800        } 
     2801 
     2802        // Order by. 
     2803        if ( empty( $q['orderby'] ) ) { 
     2804            /* 
     2805             * Boolean false or empty array blanks out ORDER BY, 
     2806             * while leaving the value unset or otherwise empty sets the default. 
     2807             */ 
     2808            if ( isset( $q['orderby'] ) && ( is_array( $q['orderby'] ) || false === $q['orderby'] ) ) { 
     2809                $orderby = ''; 
     2810            } else { 
     2811                $orderby = "$wpdb->posts.post_date " . $q['order']; 
     2812            } 
    27112813        } elseif ( 'none' == $q['orderby'] ) { 
    27122814            $orderby = ''; 
     
    27162818            $orderby = "FIELD( {$wpdb->posts}.post_parent, $post_parent__in )"; 
    27172819        } else { 
    2718             // Used to filter values 
    2719             $allowed_keys = array( 'name', 'author', 'date', 'title', 'modified', 'menu_order', 'parent', 'ID', 'rand', 'comment_count', 'type' ); 
    2720             if ( !empty($q['meta_key']) ) { 
    2721                 $allowed_keys[] = $q['meta_key']; 
    2722                 $allowed_keys[] = 'meta_value'; 
    2723                 $allowed_keys[] = 'meta_value_num'; 
    2724             } 
    2725             $q['orderby'] = urldecode($q['orderby']); 
    2726             $q['orderby'] = addslashes_gpc($q['orderby']); 
    2727  
    27282820            $orderby_array = array(); 
    2729             foreach ( explode( ' ', $q['orderby'] ) as $i => $orderby ) { 
    2730                 // Only allow certain values for safety 
    2731                 if ( ! in_array($orderby, $allowed_keys) ) 
    2732                     continue; 
    2733  
    2734                 switch ( $orderby ) { 
    2735                     case 'menu_order': 
    2736                         $orderby = "$wpdb->posts.menu_order"; 
    2737                         break; 
    2738                     case 'ID': 
    2739                         $orderby = "$wpdb->posts.ID"; 
    2740                         break; 
    2741                     case 'rand': 
    2742                         $orderby = 'RAND()'; 
    2743                         break; 
    2744                     case $q['meta_key']: 
    2745                     case 'meta_value': 
    2746                         if ( isset( $q['meta_type'] ) ) { 
    2747                             $meta_type = $this->meta_query->get_cast_for_type( $q['meta_type'] ); 
    2748                             $orderby = "CAST($wpdb->postmeta.meta_value AS {$meta_type})"; 
    2749                         } else { 
    2750                             $orderby = "$wpdb->postmeta.meta_value"; 
    2751                         } 
    2752                         break; 
    2753                     case 'meta_value_num': 
    2754                         $orderby = "$wpdb->postmeta.meta_value+0"; 
    2755                         break; 
    2756                     case 'comment_count': 
    2757                         $orderby = "$wpdb->posts.comment_count"; 
    2758                         break; 
    2759                     default: 
    2760                         $orderby = "$wpdb->posts.post_" . $orderby; 
     2821            if ( is_array( $q['orderby'] ) ) { 
     2822                foreach ( $q['orderby'] as $_orderby => $order ) { 
     2823                    $orderby = addslashes_gpc( urldecode( $_orderby ) ); 
     2824                    $parsed  = $this->parse_orderby( $orderby ); 
     2825 
     2826                    if ( ! $parsed ) { 
     2827                        continue; 
     2828                    } 
     2829 
     2830                    $orderby_array[] = $parsed . ' ' . $this->parse_order( $order ); 
    27612831                } 
    2762  
    2763                 $orderby_array[] = $orderby; 
    2764             } 
    2765             $orderby = implode( ' ' . $q['order'] . ', ', $orderby_array ); 
    2766  
    2767             if ( empty( $orderby ) ) 
    2768                 $orderby = "$wpdb->posts.post_date ".$q['order']; 
    2769             else 
    2770                 $orderby .= " {$q['order']}"; 
     2832                $orderby = implode( ', ', $orderby_array ); 
     2833 
     2834            } else { 
     2835                $q['orderby'] = urldecode( $q['orderby'] ); 
     2836                $q['orderby'] = addslashes_gpc( $q['orderby'] ); 
     2837 
     2838                foreach ( explode( ' ', $q['orderby'] ) as $i => $orderby ) { 
     2839                    $parsed = $this->parse_orderby( $orderby ); 
     2840                    // Only allow certain values for safety. 
     2841                    if ( ! $parsed ) { 
     2842                        continue; 
     2843                    } 
     2844 
     2845                    $orderby_array[] = $parsed; 
     2846                } 
     2847                $orderby = implode( ' ' . $q['order'] . ', ', $orderby_array ); 
     2848 
     2849                if ( empty( $orderby ) ) { 
     2850                    $orderby = "$wpdb->posts.post_date ".$q['order']; 
     2851                } else { 
     2852                    $orderby .= " {$q['order']}"; 
     2853                } 
     2854            } 
    27712855        } 
    27722856 
  • trunk/tests/phpunit/tests/post/query.php

    r28622 r29027  
    762762        $this->assertNotContains( "post_status <> 'auto-draft'", $q3->request ); 
    763763    } 
     764 
     765    /** 
     766     * 
     767     * @ticket 17065 
     768     */ 
     769    function test_orderby_array() { 
     770        global $wpdb; 
     771 
     772        $q1 = new WP_Query( array( 
     773            'orderby' => array( 
     774                'type' => 'DESC', 
     775                'name' => 'ASC' 
     776            ) 
     777        ) ); 
     778        $this->assertContains( 
     779            "ORDER BY $wpdb->posts.post_type DESC, $wpdb->posts.post_name ASC", 
     780            $q1->request 
     781        ); 
     782 
     783        $q2 = new WP_Query( array( 'orderby' => array() ) ); 
     784        $this->assertNotContains( 'ORDER BY', $q2->request ); 
     785        $this->assertNotContains( 'ORDER', $q2->request ); 
     786 
     787        $q3 = new WP_Query( array( 'post_type' => 'post' ) ); 
     788        $this->assertContains( 
     789            "ORDER BY $wpdb->posts.post_date DESC", 
     790            $q3->request 
     791        ); 
     792 
     793        $q4 = new WP_Query( array( 'post_type' => 'post' ) ); 
     794        $this->assertContains( 
     795            "ORDER BY $wpdb->posts.post_date DESC", 
     796            $q4->request 
     797        ); 
     798    } 
     799 
     800    /** 
     801     * 
     802     * @ticket 17065 
     803     */ 
     804    function test_order() { 
     805        global $wpdb; 
     806 
     807        $q1 = new WP_Query( array( 
     808            'orderby' => array( 
     809                'post_type' => 'foo' 
     810            ) 
     811        ) ); 
     812        $this->assertContains( 
     813            "ORDER BY $wpdb->posts.post_type DESC", 
     814            $q1->request 
     815        ); 
     816 
     817        $q2 = new WP_Query( array( 
     818            'orderby' => 'title', 
     819            'order'   => 'foo' 
     820        ) ); 
     821        $this->assertContains( 
     822            "ORDER BY $wpdb->posts.post_title DESC", 
     823            $q2->request 
     824        ); 
     825 
     826        $q3 = new WP_Query( array( 
     827            'order' => 'asc' 
     828        ) ); 
     829        $this->assertContains( 
     830            "ORDER BY $wpdb->posts.post_date ASC", 
     831            $q3->request 
     832        ); 
     833    } 
    764834} 
Note: See TracChangeset for help on using the changeset viewer.