Changeset 34546
- Timestamp:
- 09/25/2015 03:12:09 PM (9 years ago)
- Location:
- trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/class-wp-comment-query.php
r34544 r34546 138 138 * @since 4.2.0 139 139 * @since 4.4.0 `$parent__in` and `$parent__not_in` were added. 140 * @since 4.4.0 Order by `comment__in` was added. `$update_comment_meta_cache` and `$no_found_rows` were added. 140 * @since 4.4.0 Order by `comment__in` was added. `$update_comment_meta_cache`, `$no_found_rows`, 141 * and `$hierarchical` were added. 141 142 * @access public 142 143 * … … 207 208 * @type array $type__not_in Exclude comments from a given array of comment types. Default empty. 208 209 * @type int $user_id Include comments for a specific user ID. Default empty. 210 * @type bool|string $hierarchical Whether to include comment descendants in the results. 211 * 'threaded' returns a tree, with each comment's children stored 212 * in a `children` property on the `WP_Comment` object. 'flat' 213 * returns a flat array of found comments plus their children. 214 * Pass `false` to leave out descendants. The parameter is ignored 215 * (forced to `false`) when `$fields` is 'ids' or 'counts'. 216 * Accepts 'threaded', 'flat', or false. Default: false. 209 217 * @type bool $update_comment_meta_cache Whether to prime the metadata cache for found comments. 210 218 * Default true. … … 250 258 'meta_query' => '', 251 259 'date_query' => null, // See WP_Date_Query 260 'hierarchical' => false, 252 261 'update_comment_meta_cache' => true, 253 262 ); … … 397 406 $comments = array_map( 'get_comment', $_comments ); 398 407 408 if ( $this->query_vars['hierarchical'] ) { 409 $comments = $this->fill_descendants( $comments ); 410 } 411 399 412 $this->comments = $comments; 400 413 return $this->comments; … … 664 677 $this->sql_clauses['where']['comment_type__' . strtolower( str_replace( ' ', '_', $operator ) ) ] = "comment_type $operator ($types_sql)"; 665 678 } 679 } 680 681 if ( $this->query_vars['hierarchical'] && ! $this->query_vars['parent'] ) { 682 $this->query_vars['parent'] = 0; 666 683 } 667 684 … … 796 813 return array_map( 'intval', $comment_ids ); 797 814 } 815 } 816 817 /** 818 * Fetch descendants for located comments. 819 * 820 * Instead of calling `get_children()` separately on each child comment, we do a single set of queries to fetch 821 * the descendant trees for all matched top-level comments. 822 * 823 * @since 4.4.0 824 * 825 * @param array $comments Array of top-level comments whose descendants should be filled in. 826 * @return array 827 */ 828 protected function fill_descendants( $comments ) { 829 global $wpdb; 830 831 $levels = array( 832 0 => wp_list_pluck( $comments, 'comment_ID' ), 833 ); 834 835 $where_clauses = $this->sql_clauses['where']; 836 unset( 837 $where_clauses['parent'], 838 $where_clauses['parent__in'], 839 $where_clauses['parent__not_in'] 840 ); 841 842 // Fetch an entire level of the descendant tree at a time. 843 $level = 0; 844 do { 845 $parent_ids = $levels[ $level ]; 846 $where = 'WHERE ' . implode( ' AND ', $where_clauses ) . ' AND comment_parent IN (' . implode( ',', array_map( 'intval', $parent_ids ) ) . ')'; 847 $comment_ids = $wpdb->get_col( "{$this->sql_clauses['select']} {$this->sql_clauses['from']} {$where} {$this->sql_clauses['groupby']}" ); 848 849 $level++; 850 $levels[ $level ] = $comment_ids; 851 } while ( $comment_ids ); 852 853 // Prime comment caches for non-top-level comments. 854 $descendant_ids = array(); 855 for ( $i = 1; $i < count( $levels ); $i++ ) { 856 $descendant_ids = array_merge( $descendant_ids, $levels[ $i ] ); 857 } 858 859 _prime_comment_caches( $descendant_ids, $this->query_vars['update_comment_meta_cache'] ); 860 861 // Assemble a flat array of all comments + descendants. 862 $all_comments = $comments; 863 foreach ( $descendant_ids as $descendant_id ) { 864 $all_comments[] = get_comment( $descendant_id ); 865 } 866 867 // If a threaded representation was requested, build the tree. 868 if ( 'threaded' === $this->query_vars['hierarchical'] ) { 869 $threaded_comments = $ref = array(); 870 foreach ( $all_comments as $k => $c ) { 871 $_c = get_comment( $c->comment_ID ); 872 873 // If the comment isn't in the reference array, it goes in the top level of the thread. 874 if ( ! isset( $ref[ $c->comment_parent ] ) ) { 875 $threaded_comments[ $_c->comment_ID ] = $_c; 876 $ref[ $_c->comment_ID ] = $threaded_comments[ $_c->comment_ID ]; 877 878 // Otherwise, set it as a child of its parent. 879 } else { 880 881 $ref[ $_c->comment_parent ]->add_child( $_c ); 882 // $ref[ $c->comment_parent ]->children[ $c->comment_ID ] = $c; 883 $ref[ $_c->comment_ID ] = $ref[ $_c->comment_parent ]->get_child( $_c->comment_ID ); 884 } 885 } 886 887 $comments = $threaded_comments; 888 } else { 889 $comments = $all_comments; 890 } 891 892 return $comments; 798 893 } 799 894 -
trunk/src/wp-includes/class-wp-comment.php
r34409 r34546 151 151 152 152 /** 153 * Comment children. 154 * 155 * @since 4.4.0 156 * @access protected 157 * @var array 158 */ 159 protected $children; 160 161 /** 153 162 * Retrieves a WP_Comment instance. 154 163 * … … 212 221 return get_object_vars( $this ); 213 222 } 223 224 /** 225 * Get the children of a comment. 226 * 227 * @since 4.4.0 228 * @access public 229 * 230 * @return array Array of `WP_Comment` objects. 231 */ 232 public function get_children() { 233 if ( is_null( $this->children ) ) { 234 $this->children = get_comments( array( 235 'parent' => $this->comment_ID, 236 'hierarchical' => 'threaded', 237 ) ); 238 } 239 240 return $this->children; 241 } 242 243 /** 244 * Add a child to the comment. 245 * 246 * Used by `WP_Comment_Query` when bulk-filling descendants. 247 * 248 * @since 4.4.0 249 * @access public 250 * 251 * @param WP_Comment $child Child comment. 252 */ 253 public function add_child( WP_Comment $child ) { 254 $this->comments[ $child->comment_ID ] = $child; 255 } 256 257 /** 258 * Get a child comment by ID. 259 * 260 * @since 4.4.0 261 * @access public 262 * 263 * @param int $child_id ID of the child. 264 * @return WP_Comment|bool Returns the comment object if found, otherwise false. 265 */ 266 public function get_child( $child_id ) { 267 if ( isset( $this->comments[ $child_id ] ) ) { 268 return $this->comments[ $child_id ]; 269 } 270 271 return false; 272 } 214 273 } -
trunk/tests/phpunit/tests/comment.php
r34533 r34546 289 289 $this->assertEquals( 'fire', get_comment_meta( $c, 'sauce', true ) ); 290 290 } 291 292 /** 293 * @ticket 8071 294 */ 295 public function test_wp_comment_get_children_should_fill_children() { 296 297 $p = $this->factory->post->create(); 298 299 $c1 = $this->factory->comment->create( array( 300 'comment_post_ID' => $p, 301 'comment_approved' => '1', 302 ) ); 303 304 $c2 = $this->factory->comment->create( array( 305 'comment_post_ID' => $p, 306 'comment_approved' => '1', 307 'comment_parent' => $c1, 308 ) ); 309 310 $c3 = $this->factory->comment->create( array( 311 'comment_post_ID' => $p, 312 'comment_approved' => '1', 313 'comment_parent' => $c2, 314 ) ); 315 316 $c4 = $this->factory->comment->create( array( 317 'comment_post_ID' => $p, 318 'comment_approved' => '1', 319 'comment_parent' => $c1, 320 ) ); 321 322 $c5 = $this->factory->comment->create( array( 323 'comment_post_ID' => $p, 324 'comment_approved' => '1', 325 ) ); 326 327 $c6 = $this->factory->comment->create( array( 328 'comment_post_ID' => $p, 329 'comment_approved' => '1', 330 'comment_parent' => $c5, 331 ) ); 332 333 $comment = get_comment( $c1 ); 334 $children = $comment->get_children(); 335 336 // Direct descendants of $c1. 337 $this->assertEquals( array( $c2, $c4 ), array_values( wp_list_pluck( $children, 'comment_ID' ) ) ); 338 339 // Direct descendants of $c2. 340 $this->assertEquals( array( $c3 ), array_values( wp_list_pluck( $children[ $c2 ]->get_children(), 'comment_ID' ) ) ); 341 } 291 342 } -
trunk/tests/phpunit/tests/comment/query.php
r34544 r34546 1921 1921 $this->assertEquals( 2, $q->max_num_pages ); 1922 1922 } 1923 1924 /** 1925 * @ticket 8071 1926 */ 1927 public function test_hierarchical_should_skip_child_comments_in_offset() { 1928 $top_level_0 = $this->factory->comment->create( array( 1929 'comment_post_ID' => $this->post_id, 1930 'comment_approved' => '1', 1931 ) ); 1932 1933 $child_of_0 = $this->factory->comment->create( array( 1934 'comment_post_ID' => $this->post_id, 1935 'comment_approved' => '1', 1936 'comment_parent' => $top_level_0, 1937 ) ); 1938 1939 $top_level_comments = $this->factory->comment->create_many( 3, array( 1940 'comment_post_ID' => $this->post_id, 1941 'comment_approved' => '1', 1942 ) ); 1943 1944 $q = new WP_Comment_Query( array( 1945 'post_id' => $this->post_id, 1946 'hierarchical' => 'flat', 1947 'number' => 2, 1948 'offset' => 1, 1949 'orderby' => 'comment_ID', 1950 'order' => 'ASC', 1951 'fields' => 'ids', 1952 ) ); 1953 1954 $this->assertEquals( array( $top_level_comments[0], $top_level_comments[1] ), $q->comments ); 1955 } 1956 1957 /** 1958 * @ticket 8071 1959 */ 1960 public function test_hierarchical_should_not_include_child_comments_in_number() { 1961 $top_level_0 = $this->factory->comment->create( array( 1962 'comment_post_ID' => $this->post_id, 1963 'comment_approved' => '1', 1964 ) ); 1965 1966 $child_of_0 = $this->factory->comment->create( array( 1967 'comment_post_ID' => $this->post_id, 1968 'comment_approved' => '1', 1969 'comment_parent' => $top_level_0, 1970 ) ); 1971 1972 $top_level_comments = $this->factory->comment->create_many( 3, array( 1973 'comment_post_ID' => $this->post_id, 1974 'comment_approved' => '1', 1975 ) ); 1976 1977 $q = new WP_Comment_Query( array( 1978 'post_id' => $this->post_id, 1979 'hierarchical' => 'flat', 1980 'number' => 2, 1981 'orderby' => 'comment_ID', 1982 'order' => 'ASC', 1983 ) ); 1984 1985 $this->assertEqualSets( array( $top_level_0, $child_of_0, $top_level_comments[0] ), wp_list_pluck( $q->comments, 'comment_ID' ) ); 1986 } 1987 1988 /** 1989 * @ticket 8071 1990 */ 1991 public function test_hierarchical_threaded() { 1992 $c1 = $this->factory->comment->create( array( 1993 'comment_post_ID' => $this->post_id, 1994 'comment_approved' => '1', 1995 ) ); 1996 1997 $c2 = $this->factory->comment->create( array( 1998 'comment_post_ID' => $this->post_id, 1999 'comment_approved' => '1', 2000 'comment_parent' => $c1, 2001 ) ); 2002 2003 $c3 = $this->factory->comment->create( array( 2004 'comment_post_ID' => $this->post_id, 2005 'comment_approved' => '1', 2006 'comment_parent' => $c2, 2007 ) ); 2008 2009 $c4 = $this->factory->comment->create( array( 2010 'comment_post_ID' => $this->post_id, 2011 'comment_approved' => '1', 2012 'comment_parent' => $c1, 2013 ) ); 2014 2015 $c5 = $this->factory->comment->create( array( 2016 'comment_post_ID' => $this->post_id, 2017 'comment_approved' => '1', 2018 ) ); 2019 2020 $c6 = $this->factory->comment->create( array( 2021 'comment_post_ID' => $this->post_id, 2022 'comment_approved' => '1', 2023 'comment_parent' => $c5, 2024 ) ); 2025 2026 $q = new WP_Comment_Query( array( 2027 'post_id' => $this->post_id, 2028 'hierarchical' => 'threaded', 2029 'orderby' => 'comment_ID', 2030 'order' => 'ASC', 2031 ) ); 2032 2033 // Top-level comments. 2034 $this->assertEquals( array( $c1, $c5 ), array_values( wp_list_pluck( $q->comments, 'comment_ID' ) ) ); 2035 2036 // Direct descendants of $c1. 2037 $this->assertEquals( array( $c2, $c4 ), array_values( wp_list_pluck( $q->comments[ $c1 ]->get_children(), 'comment_ID' ) ) ); 2038 2039 // Direct descendants of $c2. 2040 $this->assertEquals( array( $c3 ), array_values( wp_list_pluck( $q->comments[ $c1 ]->get_child( $c2 )->get_children(), 'comment_ID' ) ) ); 2041 2042 // Direct descendants of $c5. 2043 $this->assertEquals( array( $c6 ), array_values( wp_list_pluck( $q->comments[ $c5 ]->get_children(), 'comment_ID' ) ) ); 2044 } 1923 2045 }
Note: See TracChangeset
for help on using the changeset viewer.