-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add caching to count_user_posts. #8233
base: trunk
Are you sure you want to change the base?
Conversation
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Unlinked AccountsThe following contributors have not linked their GitHub and WordPress.org accounts: @jonnynews. Contributors, please read how to link your accounts to ensure your work is properly credited in WordPress releases. Core Committers: Use this line as a base for the props when committing in SVN:
To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, @spacedmonkey!
PR looks good and matches similar optimizations you worked on a couple of years ago - dfcfe0b.
I trust your judgment regarding unit test coverage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple of suggestions inline.
I added the following to tests/phpunit/tests/user/countUserPosts.php
while reviewing and testing the code.
/**
* User 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() {
$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',
)
);
// 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 );
}
/**
* 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 );
}
Co-authored-by: Peter Wilson <[email protected]>
Introduce tests to validate count_user_posts correctness for non-existent users, users created after post assignment, and caching mechanisms. Ensure accurate caching for post type order variations and equivalence of string and array queries. Feedback from @peterwilsoncc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@peterwilsoncc Thanks for the tests. Complete legend. Added your feedback.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @spacedmonkey, this looks good to me.
I missed a coupe of things while writing up the tests so have pushed a minor change and taken the opportunity to merge in trunk while doing so.
src/wp-includes/user.php
Outdated
@@ -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) $post_type; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$post_type = (array) $post_type; | |
$post_type = array_filter( array_unique( (array) $post_type ), 'post_type_exists' ); |
@peterwilsoncc What do you think of this? Overkill?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
array_unique()
would help, get_posts_by_author_sql()
already ensures the post type exists so no need to do it here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well that's the point, this code would result in hitting the cache, as the cache key would match.
So
count_user_posts( 1, array( 'post', 'invalid' ) );
Or
count_user_posts( 1, array( 'post', '' ) );
Would be the same as
count_user_posts( 1, array( 'post') );
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what I am saying, they should already hit the cache as the it's generated based on the SQL without taking in to account the arguments passed to the function.
Ensure array duplicates and equivalent queries are correctly handled by using unique post types in count_user_posts. Added PHPUnit tests to verify cache hits for these scenarios, improving performance.
@JJJ @swissspidy Are you interested in reviewing PR? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@spacedmonkey This looks great, thanks!
@spacedmonkey Had a quick glance earlier today and I think it's a neat way to add this enhancement without having to make too many changes like in the other PRs. You have plenty of approvals already though :-) |
It more to check to see if you are strongly against it. I know you were worried about this cache being invalidated a lot, but honestly I dont see a way around it. |
* User count cache should be hit for array duplicates and equivalent queries. | ||
* | ||
* @ticket 39242 | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation
count_user_posts( self::$user_id, array( 'post' ) ); | ||
$total_queries = get_num_queries() - $query_num_start; | ||
|
||
$this->assertSame( 0, $total_queries ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$this->assertSame( 0, $total_queries ); | |
$this->assertSame( 0, $total_queries, 'Cache is expected to be hit for equivalent queries with duplicate post types' ); |
Happy to! Incrementally, I like it. Specifically:
Tangential thoughts while reviewing...
Long term, I also like that @swissspidy included Perhaps that gets its own issue/ticket? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Sorry, I'm unclear what you are asking here but I possibly answer your question next...
It doesn't within
Possibly useful but as a follow up ticket. |
we can get the data using the bellow code and implement on it.
|
We can also use in tests/phpunit/tests/user/countUserPosts.php I refactored the test methods for better clarity while keeping the functionality intact. I also used assertEquals() where type coercion is acceptable and replaced unnecessary string comparisons to make the tests more robust. Additionally, I added $wpdb->num_queries to track database queries before and after calls, ensuring that the cache is being utilized properly. Let me know if you need any further refinements! |
@dilipom13 Each of those test cases are currently covered by the test suite. WordPress aims to maintain the return type of functions, so the tests need to use assertSame(). |
Simple caching based on last updated values changing.
Trac ticket: https://core.trac.wordpress.org/ticket/39242
This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.