Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 1 addition & 34 deletions src/wp-admin/includes/class-wp-privacy-requests-table.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,43 +102,10 @@ protected function get_default_primary_column_name() {
*
* @since 4.9.6
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @return object Number of posts for each status.
*/
protected function get_request_counts() {
global $wpdb;

$cache_key = $this->post_type . '-' . $this->request_type;
$counts = wp_cache_get( $cache_key, 'counts' );

if ( false !== $counts ) {
return $counts;
}

$results = (array) $wpdb->get_results(
$wpdb->prepare(
"SELECT post_status, COUNT( * ) AS num_posts
FROM {$wpdb->posts}
WHERE post_type = %s
AND post_name = %s
GROUP BY post_status",
$this->post_type,
$this->request_type
),
ARRAY_A
);

$counts = array_fill_keys( get_post_stati(), 0 );

foreach ( $results as $row ) {
$counts[ $row['post_status'] ] = $row['num_posts'];
}

$counts = (object) $counts;
wp_cache_set( $cache_key, $counts, 'counts' );

return $counts;
return wp_count_user_requests( $this->request_type );
}
Comment on lines 105 to 109

/**
Expand Down
60 changes: 60 additions & 0 deletions src/wp-includes/user.php
Original file line number Diff line number Diff line change
Expand Up @@ -4845,6 +4845,66 @@ function wp_create_user_request( $email_address = '', $action_name = '', $reques
return $request_id;
}

/**
* Counts the number of user requests for a given request type, grouped by status.
*
* @since 6.8.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $type Request type. Accepted values are `'export_personal_data'`
* and `'remove_personal_data'`.
* @return object Number of requests for each status, or an empty object for an invalid type.
*/
function wp_count_user_requests( $type = '' ) {
global $wpdb;

if ( ! in_array( $type, _wp_privacy_action_request_types(), true ) ) {
return new stdClass();
}
Comment on lines +4859 to +4864

$cache_key = 'user-request-' . $type;
$last_changed = wp_cache_get_last_changed( 'posts' );
$counts = wp_cache_get_salted( $cache_key, 'counts', $last_changed );

if ( false !== $counts ) {
/** This filter is documented in wp-includes/user.php */
return apply_filters( 'wp_count_user_requests', $counts, $type );
}

$results = (array) $wpdb->get_results(
$wpdb->prepare(
"SELECT post_status, COUNT( * ) AS num_posts
FROM {$wpdb->posts}
WHERE post_type = %s
AND post_name = %s
GROUP BY post_status",
'user_request',
$type
),
ARRAY_A
);

$counts = array_fill_keys( get_post_stati(), 0 );

foreach ( $results as $row ) {
$counts[ $row['post_status'] ] = $row['num_posts'];
}

$counts = (object) $counts;
wp_cache_set_salted( $cache_key, $counts, 'counts', $last_changed );

/**
* Filters the number of user requests for a given type, by status.
*
* @since 6.8.0
*
* @param object $counts Number of requests for each status.
* @param string $type Request type.
*/
return apply_filters( 'wp_count_user_requests', $counts, $type );
}

/**
* Gets action description from the name and return a string.
*
Expand Down
162 changes: 162 additions & 0 deletions tests/phpunit/tests/privacy/wpCountUserRequests.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
<?php
/**
* Test cases for the `wp_count_user_requests()` function.
*
* @package WordPress
* @subpackage UnitTests
* @since 6.8.0
*
* @group privacy
* @covers ::wp_count_user_requests
*/
class Tests_Privacy_wpCountUserRequests extends WP_UnitTestCase {

/**
* Export request ID.
*
* @since 6.8.0
*
* @var int $export_request_id
*/
protected static $export_request_id;

/**
* Erase request ID.
*
* @since 6.8.0
*
* @var int $erase_request_id
*/
protected static $erase_request_id;

/**
* Create fixtures.
*
* @since 6.8.0
*
* @param WP_UnitTest_Factory $factory Factory.
*/
public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
self::$export_request_id = $factory->post->create(
array(
'post_type' => 'user_request',
'post_name' => 'export_personal_data',
'post_status' => 'request-pending',
'post_title' => 'export@local.test',
)
);

self::$erase_request_id = $factory->post->create(
array(
'post_type' => 'user_request',
'post_name' => 'remove_personal_data',
'post_status' => 'request-confirmed',
'post_title' => 'erase@local.test',
)
);
}

/**
* Set up before each test.
*
* @since 6.8.0
*/
public function set_up() {
parent::set_up();
// Clear counts cache before each test.
wp_cache_delete( 'user-request-export_personal_data', 'counts' );
wp_cache_delete( 'user-request-remove_personal_data', 'counts' );
}

/**
* Returns an empty stdClass for an invalid or empty type string.
*
* @ticket 44034
*/
public function test_returns_empty_object_for_invalid_type() {
$actual_empty = wp_count_user_requests( '' );
$this->assertInstanceOf( 'stdClass', $actual_empty );
$this->assertEmpty( (array) $actual_empty );

$actual_invalid = wp_count_user_requests( 'invalid_type' );
$this->assertInstanceOf( 'stdClass', $actual_invalid );
$this->assertEmpty( (array) $actual_invalid );
}

/**
* Counts export requests correctly by status.
*
* @ticket 44034
*/
public function test_counts_export_requests_by_status() {
$actual = wp_count_user_requests( 'export_personal_data' );

$this->assertSame( 1, (int) $actual->{'request-pending'} );
$this->assertSame( 0, (int) $actual->{'request-confirmed'} );
}

/**
* Counts erase requests correctly by status.
*
* @ticket 44034
*/
public function test_counts_erase_requests_by_status() {
$actual = wp_count_user_requests( 'remove_personal_data' );

$this->assertSame( 0, (int) $actual->{'request-pending'} );
$this->assertSame( 1, (int) $actual->{'request-confirmed'} );
}

/**
* Result contains all registered post statuses as keys.
*
* @ticket 44034
*/
public function test_result_contains_all_post_statuses() {
$actual = wp_count_user_requests( 'export_personal_data' );
$stati = get_post_stati();
$actual_keys = array_keys( (array) $actual );

foreach ( $stati as $status ) {
$this->assertContains( $status, $actual_keys, "Missing status: $status" );
}
}

/**
* Result is cached after first call.
*
* @ticket 44034
*/
public function test_result_is_cached() {
wp_count_user_requests( 'export_personal_data' );

$last_changed = wp_cache_get_last_changed( 'posts' );
$cached = wp_cache_get_salted( 'user-request-export_personal_data', 'counts', $last_changed );

$this->assertNotFalse( $cached );
$this->assertInstanceOf( 'stdClass', $cached );
}

/**
* The `wp_count_user_requests` filter can modify the returned counts.
*
* @ticket 44034
*/
public function test_filter_can_modify_counts() {
add_filter(
'wp_count_user_requests',
function ( $counts, $type ) {
$this->assertSame( 'export_personal_data', $type );
$modified = new stdClass();
$modified->{'request-pending'} = 999;
return $modified;
},
10,
2
);

$actual = wp_count_user_requests( 'export_personal_data' );

$this->assertSame( 999, (int) $actual->{'request-pending'} );
}
}
Loading