Skip to content
4 changes: 2 additions & 2 deletions src/wp-includes/class-wp-post.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ final class WP_Post {
* @since 3.5.0
* @var string
*/
public $post_author = 0;
public $post_author = '0';

/**
* The post's local publication time.
Expand Down Expand Up @@ -207,7 +207,7 @@ final class WP_Post {
* @since 3.5.0
* @var string
*/
public $comment_count = 0;
public $comment_count = '0';

/**
* Stores the post object's sanitization level.
Expand Down
15 changes: 13 additions & 2 deletions src/wp-includes/comment.php
Original file line number Diff line number Diff line change
Expand Up @@ -2890,6 +2890,7 @@ function discover_pingback_server_uri( $url, $deprecated = '' ) {

$pingback_link_offset_dquote = strpos( $contents, $pingback_str_dquote );
$pingback_link_offset_squote = strpos( $contents, $pingback_str_squote );

if ( $pingback_link_offset_dquote || $pingback_link_offset_squote ) {
$quote = ( $pingback_link_offset_dquote ) ? '"' : '\'';
$pingback_link_offset = ( '"' === $quote ) ? $pingback_link_offset_dquote : $pingback_link_offset_squote;
Expand Down Expand Up @@ -3079,9 +3080,11 @@ function generic_ping( $post_id = 0 ) {
*
* @since 0.71
* @since 4.7.0 `$post` can be a WP_Post object.
* @since 6.8.0 Returns an array of pingback statuses indexed by link.
*
* @param string $content Post content to check for links. If empty will retrieve from post.
* @param int|WP_Post $post Post ID or object.
* @return array<string, bool> An array of pingback statuses indexed by link.
*/
function pingback( $content, $post ) {
require_once ABSPATH . WPINC . '/class-IXR.php';
Expand All @@ -3093,7 +3096,7 @@ function pingback( $content, $post ) {
$post = get_post( $post );

if ( ! $post ) {
return;
return array();
}

$pung = get_pung( $post );
Expand All @@ -3108,6 +3111,7 @@ function pingback( $content, $post ) {
*/
$post_links_temp = wp_extract_urls( $content );

$ping_status = array();
/*
* Step 2.
* Walking through the links array.
Expand Down Expand Up @@ -3179,11 +3183,18 @@ function pingback( $content, $post ) {
// When set to true, this outputs debug messages by itself.
$client->debug = false;

if ( $client->query( 'pingback.ping', $pagelinkedfrom, $pagelinkedto ) || ( isset( $client->error->code ) && 48 == $client->error->code ) ) { // Already registered.
$status = $client->query( 'pingback.ping', $pagelinkedfrom, $pagelinkedto );

if ( $status // Ping registered.
|| ( isset( $client->error->code ) && 48 === $client->error->code ) // Already registered.
) {
add_ping( $post, $pagelinkedto );
}
$ping_status[ $pagelinkedto ] = $status;
}
}

return $ping_status;
}

/**
Expand Down
12 changes: 11 additions & 1 deletion src/wp-includes/user.php
Original file line number Diff line number Diff line change
Expand Up @@ -604,9 +604,19 @@ function wp_validate_logged_in_cookie( $user_id ) {
function count_user_posts( $userid, $post_type = 'post', $public_only = false ) {
global $wpdb;

$post_type = array_unique( (array) $post_type );
sort( $post_type );

$where = get_posts_by_author_sql( $post_type, true, $userid, $public_only );
$query = "SELECT COUNT(*) FROM $wpdb->posts $where";

$count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts $where" );
$last_changed = wp_cache_get_last_changed( 'posts' );
$cache_key = 'count_user_posts:' . md5( $query ) . ':' . $last_changed;
$count = wp_cache_get( $cache_key, 'post-queries' );
if ( false === $count ) {
$count = $wpdb->get_var( $query );
wp_cache_set( $cache_key, $count, 'post-queries' );
}

/**
* Filters the number of posts a user has written.
Expand Down
92 changes: 92 additions & 0 deletions tests/phpunit/tests/comment/pingback.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php

// Test the output of Comment Querying functions.

/**
* @group comment
*/
class Tests_Comment_Pingback extends WP_UnitTestCase {

protected static $post_id;
protected $response = array();

public function set_up() {
parent::set_up();

add_filter( 'pre_http_request', array( $this, 'request_response' ) );
}

public function tear_down() {
remove_filter( 'pre_http_request', array( $this, 'request_response' ) );
parent::tear_down();
}

public function test_pingback() {
$content = <<<HTML
<a href="http://example.org">test</a>
<a href="http://example1.org/test">test</a>
<a href="http://example3.org/">test</a>
HTML;

$body = <<<BODY
<a rel="pingback" href="https://example1.org/test/pingback">test</a>
BODY;

$this->response = array(
'body' => $body,
'response' => array( 'code' => 200 ),
);

self::$post_id = self::factory()->post->create(
array( 'post_content' => $content )
);

$post = get_post( self::$post_id );
$this->assertEquals( array( 'http://example1.org/test' => false ), pingback( $post->post_content, self::$post_id ) );
}

public function test_pingback_no_ping_back() {
$content = <<<HTML
<a href="http://example.org">test</a>
<a href="http://example1.org/test">test</a>
<a href="http://example3.org/">test</a>
HTML;

$body = <<<BODY
<a href="https://example1.org/test">test</a>
BODY;

$this->response = array(
'body' => $body,
'response' => array( 'code' => 200 ),
);

self::$post_id = self::factory()->post->create(
array( 'post_content' => $content )
);

$post = get_post( self::$post_id );
$this->assertEquals( array(), pingback( $post->post_content, self::$post_id ) );
}

public function test_pingback_error_response() {
$content = <<<HTML
<a href="http://example.org">test</a>
<a href="http://example1.org/test">test</a>
<a href="http://example3.org/">test</a>
HTML;

$this->response = new WP_Error();

self::$post_id = self::factory()->post->create(
array( 'post_content' => $content )
);

$post = get_post( self::$post_id );
$this->assertEquals( array(), pingback( $post->post_content, self::$post_id ) );
}

public function request_response() {
return $this->response;
}
}
138 changes: 138 additions & 0 deletions tests/phpunit/tests/user/countUserPosts.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,142 @@ public function test_count_user_posts_with_multiple_post_types() {
public function test_count_user_posts_should_ignore_non_existent_post_types() {
$this->assertSame( '4', count_user_posts( self::$user_id, array( 'foo', 'post' ) ) );
}

/**
* Post count be correct after reassigning posts to another user.
*
* @ticket 39242
*/
public function test_reassigning_users_posts_modifies_count() {
// Create new user.
$new_user_id = self::factory()->user->create(
array(
'role' => 'author',
)
);

// Prior to reassigning posts.
$this->assertSame( '4', count_user_posts( self::$user_id ), 'Original user is expected to have a count of four posts prior to reassignment.' );
$this->assertSame( '0', count_user_posts( $new_user_id ), 'New user is expected to have a count of zero posts prior to reassignment.' );

// Delete the original user, reassigning their posts to the new user.
wp_delete_user( self::$user_id, $new_user_id );

// After reassigning posts.
$this->assertSame( '0', count_user_posts( self::$user_id ), 'Original user is expected to have a count of zero posts following reassignment.' );
$this->assertSame( '4', count_user_posts( $new_user_id ), 'New user is expected to have a count of four posts following reassignment.' );
}

/**
* Post count be correct after deleting user without reassigning posts.
*
* @ticket 39242
*/
public function test_post_count_retained_after_deleting_user_without_reassigning_posts() {
$this->assertSame( '4', count_user_posts( self::$user_id ), 'User is expected to have a count of four posts prior to deletion.' );

// Delete the original user without reassigning their posts.
wp_delete_user( self::$user_id );

$this->assertSame( '0', count_user_posts( self::$user_id ), 'User is expected to have a count of zero posts following deletion.' );
}

/**
* Post count should work for users that don't exist but have posts assigned.
*
* @ticket 39242
*/
public function test_count_user_posts_for_non_existent_user() {
$next_user_id = self::$user_id + 1;

// Assign post to next user.
self::factory()->post->create(
array(
'post_author' => $next_user_id,
'post_type' => 'post',
)
);

$next_user_post_count = count_user_posts( $next_user_id );
$this->assertSame( '1', $next_user_post_count, 'Non-existent user is expected to have count of one post.' );
}

/**
* Cached user count value should be accurate after user is created.
*
* @ticket 39242
*/
public function test_count_user_posts_for_user_created_after_being_assigned_posts() {
global $wpdb;
$next_user_id = (int) $wpdb->get_var( "SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES WHERE table_name = '$wpdb->users'" );

// Assign post to next user.
self::factory()->post->create(
array(
'post_author' => $next_user_id,
'post_type' => 'post',
)
);

// Cache the user count.
count_user_posts( $next_user_id );

// Create user.
$real_next_user_id = self::factory()->user->create(
array(
'role' => 'author',
)
);

$this->assertSame( $next_user_id, $real_next_user_id, 'User ID should match calculated value' );
$this->assertSame( '1', count_user_posts( $next_user_id ), 'User is expected to have count of one post.' );
}

/**
* User count cache should be hit regardless of post type order.
*
* @ticket 39242
*/
public function test_cache_should_be_hit_regardless_of_post_type_order() {
// Prime Cache.
count_user_posts( self::$user_id, array( 'wptests_pt', 'post' ) );

$query_num_start = get_num_queries();
count_user_posts( self::$user_id, array( 'post', 'wptests_pt' ) );
$total_queries = get_num_queries() - $query_num_start;

$this->assertSame( 0, $total_queries, 'Cache should be hit regardless of post type order.' );
}

/**
* User count cache should be hit for string and array of post types.
*
* @ticket 39242
*/
public function test_cache_should_be_hit_for_string_and_array_equivalent_queries() {
// Prime Cache.
count_user_posts( self::$user_id, 'post' );

$query_num_start = get_num_queries();
count_user_posts( self::$user_id, array( 'post' ) );
$total_queries = get_num_queries() - $query_num_start;

$this->assertSame( 0, $total_queries, 'Cache should be hit for string and array equivalent post types.' );
}

/**
* User count cache should be hit for array duplicates and equivalent queries.
*
* @ticket 39242
*/
public function test_cache_should_be_hit_for_and_array_duplicates_equivalent_queries() {
// Prime Cache
count_user_posts( self::$user_id, array( 'post', 'post', 'post' ) );

$query_num_start = get_num_queries();
count_user_posts( self::$user_id, array( 'post' ) );
$total_queries = get_num_queries() - $query_num_start;

$this->assertSame( 0, $total_queries, 'Cache is expected to be hit for equivalent queries with duplicate post types' );
}
}
Loading