From b2332718a1d0b58da1d38b7d759e6cfe3176f5e4 Mon Sep 17 00:00:00 2001 From: Boone Gorges Date: Sat, 7 Mar 2015 01:14:31 +0000 Subject: [PATCH] When passing `$full` to `get_posts_by_author_sql()`, make sure a 'post_type' clause is included in results. This change makes the 'post_type' clause in `wp_list_authors()` redundant, so we remove it. Third-party plugins using `get_posts_by_author_sql()` may have similarly redundant clauses, but this won't change the results returned by the SQL queries. Also adds unit tests for `get_posts_by_author_sql()`. Props pbearne. Fixes #30354. git-svn-id: https://develop.svn.wordpress.org/trunk@31653 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/author-template.php | 2 +- src/wp-includes/post.php | 27 ++-- .../tests/post/getPostsByAuthorSql.php | 115 ++++++++++++++++++ 3 files changed, 129 insertions(+), 15 deletions(-) create mode 100644 tests/phpunit/tests/post/getPostsByAuthorSql.php diff --git a/src/wp-includes/author-template.php b/src/wp-includes/author-template.php index 491689a7d8..0ec3e9a68e 100644 --- a/src/wp-includes/author-template.php +++ b/src/wp-includes/author-template.php @@ -337,7 +337,7 @@ function wp_list_authors( $args = '' ) { $authors = get_users( $query_args ); $author_count = array(); - foreach ( (array) $wpdb->get_results( "SELECT DISTINCT post_author, COUNT(ID) AS count FROM $wpdb->posts WHERE post_type = 'post' AND " . get_private_posts_cap_sql( 'post' ) . " GROUP BY post_author" ) as $row ) { + foreach ( (array) $wpdb->get_results( "SELECT DISTINCT post_author, COUNT(ID) AS count FROM $wpdb->posts WHERE " . get_private_posts_cap_sql( 'post' ) . " GROUP BY post_author" ) as $row ) { $author_count[$row->post_author] = $row->count; } foreach ( $authors as $author_id ) { diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index f7654f0f72..981601bd2c 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -5344,35 +5344,34 @@ function get_posts_by_author_sql( $post_type, $full = true, $post_author = null, $cap = $post_type_obj->cap->read_private_posts; } - if ( $full ) { - if ( null === $post_author ) { - $sql = $wpdb->prepare( 'WHERE post_type = %s AND ', $post_type ); - } else { - $sql = $wpdb->prepare( 'WHERE post_author = %d AND post_type = %s AND ', $post_author, $post_type ); - } - } else { - $sql = ''; + $sql = $wpdb->prepare( 'post_type = %s', $post_type ); + + if ( null !== $post_author ) { + $sql .= $wpdb->prepare( ' AND post_author = %d', $post_author ); } - $sql .= "(post_status = 'publish'"; - // Only need to check the cap if $public_only is false. + $post_status_sql = "post_status = 'publish'"; if ( false === $public_only ) { if ( current_user_can( $cap ) ) { // Does the user have the capability to view private posts? Guess so. - $sql .= " OR post_status = 'private'"; + $post_status_sql .= " OR post_status = 'private'"; } elseif ( is_user_logged_in() ) { // Users can view their own private posts. $id = get_current_user_id(); if ( null === $post_author || ! $full ) { - $sql .= " OR post_status = 'private' AND post_author = $id"; + $post_status_sql .= " OR post_status = 'private' AND post_author = $id"; } elseif ( $id == (int) $post_author ) { - $sql .= " OR post_status = 'private'"; + $post_status_sql .= " OR post_status = 'private'"; } // else none } // else none } - $sql .= ')'; + $sql .= " AND ($post_status_sql)"; + + if ( $full ) { + $sql = 'WHERE ' . $sql; + } return $sql; } diff --git a/tests/phpunit/tests/post/getPostsByAuthorSql.php b/tests/phpunit/tests/post/getPostsByAuthorSql.php new file mode 100644 index 0000000000..4c5f33dfb4 --- /dev/null +++ b/tests/phpunit/tests/post/getPostsByAuthorSql.php @@ -0,0 +1,115 @@ +assertContains( "post_type = 'post'", $maybe_string ); + } + + public function test_post_type_page(){ + $maybe_string = get_posts_by_author_sql( 'page' ); + $this->assertContains( "post_type = 'page'", $maybe_string ); + } + + public function test_non_existent_post_type(){ + $maybe_string = get_posts_by_author_sql( 'non_existent_post_type' ); + $this->assertContains( '1 = 0', $maybe_string ); + } + + public function test_full_true(){ + $maybe_string = get_posts_by_author_sql( 'post', true ); + $this->assertRegExp( '/^WHERE /', $maybe_string ); + } + + public function test_full_false(){ + $maybe_string = get_posts_by_author_sql( 'post', false ); + $this->assertNotRegExp( '/^WHERE /', $maybe_string ); + } + + public function test_post_type_clause_should_be_included_when_full_is_true(){ + $maybe_string = get_posts_by_author_sql( 'post', true ); + $this->assertContains( "post_type = 'post'", $maybe_string ); + } + + public function test_post_type_clause_should_be_included_when_full_is_false(){ + $maybe_string = get_posts_by_author_sql( 'post', false ); + $this->assertContains( "post_type = 'post'", $maybe_string ); + } + + public function test_post_author_should_create_post_author_clause(){ + $maybe_string = get_posts_by_author_sql( 'post', true, 1 ); + $this->assertContains( 'post_author = 1', $maybe_string ); + } + + public function test_public_only_true_should_not_allow_any_private_posts_for_loggedin_user(){ + $current_user = get_current_user_id(); + $u = $this->factory->user->create(); + wp_set_current_user( $u ); + + $maybe_string = get_posts_by_author_sql( 'post', true, $u, true ); + $this->assertNotContains( "post_status = 'private'", $maybe_string ); + + wp_set_current_user( $current_user ); + } + + public function test_public_only_should_default_to_false(){ + $current_user = get_current_user_id(); + $u = $this->factory->user->create(); + wp_set_current_user( $u ); + + $this->assertSame( get_posts_by_author_sql( 'post', true, $u, false ), get_posts_by_author_sql( 'post', true, $u ) ); + + wp_set_current_user( $current_user ); + } + + public function test_public_only_false_should_allow_current_user_access_to_own_private_posts_when_current_user_matches_post_author(){ + $current_user = get_current_user_id(); + $u = $this->factory->user->create(); + wp_set_current_user( $u ); + + $maybe_string = get_posts_by_author_sql( 'post', true, $u, false ); + $this->assertContains( "post_status = 'private'", $maybe_string ); + + wp_set_current_user( $current_user ); + } + + public function test_public_only_false_should_not_allow_access_to_private_posts_if_current_user_is_not_post_author(){ + $current_user = get_current_user_id(); + $u1 = $this->factory->user->create(); + $u2 = $this->factory->user->create(); + wp_set_current_user( $u1 ); + + $maybe_string = get_posts_by_author_sql( 'post', true, $u2, false ); + $this->assertNotContains( "post_status = 'private'", $maybe_string ); + + wp_set_current_user( $current_user ); + } + + public function test_public_only_false_should_allow_current_user_access_to_own_private_posts_when_post_author_is_not_provided(){ + $current_user = get_current_user_id(); + $u = $this->factory->user->create(); + wp_set_current_user( $u ); + + $maybe_string = get_posts_by_author_sql( 'post', true, $u, false ); + $this->assertContains( "post_status = 'private'", $maybe_string ); + $this->assertContains( "post_author = $u", $maybe_string ); + + wp_set_current_user( $current_user ); + } + + public function test_administrator_should_have_access_to_private_posts_when_public_only_is_false(){ + $current_user = get_current_user_id(); + $u = $this->factory->user->create( array( 'role' => 'administrator' ) ); + wp_set_current_user( $u ); + + $maybe_string = get_posts_by_author_sql( 'post', true, null, false ); + $this->assertContains( "post_status = 'private'", $maybe_string ); + $this->assertNotContains( 'post_author', $maybe_string ); + + wp_set_current_user( $current_user ); + } +}