Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 126
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
WPCOM_JSON_API_Bulk_Update_Comments_Endpoint
0.00% covered (danger)
0.00%
0 / 63
0.00% covered (danger)
0.00%
0 / 6
992
0.00% covered (danger)
0.00%
0 / 1
 callback
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
110
 validate_status_param
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 validate_empty_status_param
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 bulk_update_comments_status
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
132
 bulk_delete_comments
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
30
 delete_all
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
1<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2/**
3 * Endpoints: /sites/%s/comments/status
4 *            /sites/%s/comments/delete
5 */
6
7if ( ! defined( 'ABSPATH' ) ) {
8    exit( 0 );
9}
10
11new WPCOM_JSON_API_Bulk_Update_Comments_Endpoint(
12    array(
13        'description'          => 'Update multiple comment\'s status.',
14        'group'                => 'comments',
15        'stat'                 => 'comments:1:bulk-update-status',
16        'min_version'          => '1',
17        'max_version'          => '1',
18        'method'               => 'POST',
19        'path'                 => '/sites/%s/comments/status',
20        'path_labels'          => array(
21            '$site' => '(int|string) Site ID or domain',
22        ),
23        'request_format'       => array(
24            'comment_ids' => '(array|string) An array, or comma-separated list, of Comment IDs to update.',
25            'status'      => '(string) The new status value. Allowed values: approved, unapproved, spam, trash',
26        ),
27        'response_format'      => array(
28            'results' => '(array) An array of updated Comment IDs.',
29        ),
30        'example_request'      => 'https://public-api.wordpress.com/rest/v1/sites/82974409/comments/status',
31        'example_request_data' => array(
32            'headers' => array(
33                'authorization' => 'Bearer YOUR_API_TOKEN',
34            ),
35            'body'    => array(
36                'comment_ids' => array( 881, 882 ),
37                'status'      => 'approved',
38            ),
39        ),
40    )
41);
42
43new WPCOM_JSON_API_Bulk_Update_Comments_Endpoint(
44    array(
45        'description'          => 'Permanently delete multiple comments. Note: this request will send non-trashed comments to the trash. Trashed comments will be permanently deleted.',
46        'group'                => 'comments',
47        'stat'                 => 'comments:1:bulk-delete',
48        'min_version'          => '1',
49        'max_version'          => '1',
50        'method'               => 'POST',
51        'path'                 => '/sites/%s/comments/delete',
52        'path_labels'          => array(
53            '$site' => '(int|string) Site ID or domain',
54        ),
55        'request_format'       => array(
56            'comment_ids'  => '(array|string) An array, or comma-separated list, of Comment IDs to delete or trash. (optional)',
57            'empty_status' => '(string) Force to permanently delete all spam or trash comments. (optional). Allowed values: spam, trash',
58        ),
59        'response_format'      => array(
60            'results' => '(array) An array of deleted or trashed Comment IDs.',
61        ),
62        'example_request'      => 'https://public-api.wordpress.com/rest/v1/sites/82974409/comments/delete',
63        'example_request_data' => array(
64            'headers' => array(
65                'authorization' => 'Bearer YOUR_API_TOKEN',
66            ),
67            'body'    => array(
68                'comment_ids' => array( 881, 882 ),
69            ),
70        ),
71    )
72);
73
74/**
75 * Bulk update comments endpoint class.
76 *
77 * @phan-constructor-used-for-side-effects
78 */
79class WPCOM_JSON_API_Bulk_Update_Comments_Endpoint extends WPCOM_JSON_API_Endpoint {
80    /**
81     * API callback.
82     *
83     * @param string $path - the path.
84     * @param int    $blog_id - the blog ID.
85     */
86    public function callback( $path = '', $blog_id = 0 ) {
87        $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) );
88        if ( is_wp_error( $blog_id ) ) {
89            return $blog_id;
90        }
91
92        $input = $this->input();
93
94        if ( isset( $input['comment_ids'] ) && is_array( $input['comment_ids'] ) ) {
95            $comment_ids = $input['comment_ids'];
96        } elseif ( isset( $input['comment_ids'] ) && ! empty( $input['comment_ids'] ) ) {
97            $comment_ids = explode( ',', $input['comment_ids'] );
98        } else {
99            $comment_ids = array();
100        }
101
102        $result = array(
103            'results' => array(),
104        );
105
106        wp_defer_comment_counting( true );
107
108        if ( $this->api->ends_with( $path, '/delete' ) ) {
109            if ( isset( $input['empty_status'] ) && $this->validate_empty_status_param( $input['empty_status'] ) ) {
110                $result['results'] = $this->delete_all( $input['empty_status'] );
111            } else {
112                $result['results'] = $this->bulk_delete_comments( $comment_ids );
113            }
114        } else {
115            $status            = isset( $input['status'] ) ? $input['status'] : '';
116            $result['results'] = $this->bulk_update_comments_status( $comment_ids, $status );
117        }
118
119        wp_defer_comment_counting( false );
120
121        return $result;
122    }
123
124    /**
125     * Determine if the passed comment status is valid or not.
126     *
127     * @param string $status - status of passed comment.
128     *
129     * @return boolean
130     */
131    public function validate_status_param( $status ) {
132        return in_array( $status, array( 'approved', 'unapproved', 'pending', 'spam', 'trash' ), true );
133    }
134
135    /**
136     * Determine if the passed empty status is valid or not.
137     *
138     * @param string $empty_status - empty_status of comment.
139     *
140     * @return boolean
141     */
142    public function validate_empty_status_param( $empty_status ) {
143        return in_array( $empty_status, array( 'spam', 'trash' ), true );
144    }
145
146    /**
147     * Update the status of multiple comments.
148     *
149     * @param array  $comment_ids Comments to update.
150     * @param string $status New status value.
151     *
152     * @return array Updated comments IDs.
153     */
154    public function bulk_update_comments_status( $comment_ids, $status ) {
155        if ( count( $comment_ids ) < 1 ) {
156            return new WP_Error( 'empty_comment_ids', 'The request must include comment_ids', 400 );
157        }
158        if ( ! $this->validate_status_param( $status ) ) {
159            return new WP_Error( 'invalid_status', "Invalid comment status value provided: '$status'.", 400 );
160        }
161        $results = array();
162        foreach ( $comment_ids as $comment_id ) {
163            if ( ! current_user_can( 'edit_comment', $comment_id ) ) {
164                continue;
165            }
166            $result = false;
167            switch ( $status ) {
168                case 'approved':
169                    $result = wp_set_comment_status( $comment_id, 'approve' );
170                    break;
171                case 'unapproved':
172                case 'pending':
173                    $result = wp_set_comment_status( $comment_id, 'hold' );
174                    break;
175                case 'spam':
176                    $result = wp_spam_comment( $comment_id );
177                    break;
178                case 'trash':
179                    $result = wp_trash_comment( $comment_id );
180                    break;
181            }
182            if ( $result ) {
183                $results[] = $comment_id;
184            }
185        }
186        return $results;
187    }
188
189    /**
190     * Permanenty delete multiple comments.
191     *
192     * Comments are only permanently deleted if trash is disabled or their status is `trash` or `spam`.
193     * Otherwise they are moved to trash.
194     *
195     * @param array $comment_ids Comments to trash or delete.
196     *
197     * @return array Deleted comments IDs.
198     */
199    public function bulk_delete_comments( $comment_ids ) {
200        if ( count( $comment_ids ) < 1 ) {
201            return new WP_Error( 'empty_comment_ids', 'The request must include comment_ids', 400 );
202        }
203        $results = array();
204        foreach ( $comment_ids as $comment_id ) {
205            if ( ! current_user_can( 'edit_comment', $comment_id ) ) {
206                continue;
207            }
208            if ( wp_delete_comment( $comment_id ) ) {
209                $results[] = $comment_id;
210            }
211        }
212        return $results;
213    }
214
215    /**
216     * Delete all spam or trash comments.
217     *
218     * Comments are only permanently deleted if trash is disabled or their status is `trash` or `spam`.
219     * Otherwise they are moved to trash.
220     *
221     * @param string $status Can be `spam` or `trash`.
222     *
223     * @return array Deleted comments IDs.
224     */
225    public function delete_all( $status ) {
226        global $wpdb;
227        // This could potentially take a long time, so we only want to delete comments created
228        // before this operation.
229        // Comments marked `spam` or `trash` after this moment won't be touched.
230        // Core uses the `pagegen_timestamp` hidden field for this same reason.
231        $delete_time = gmdate( 'Y-m-d H:i:s' );
232        $comment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_approved = %s AND %s > comment_date_gmt", $status, $delete_time ) );
233
234        if ( ! is_countable( $comment_ids ) || array() === $comment_ids ) {
235            return array();
236        }
237
238        return $this->bulk_delete_comments( $comment_ids );
239    }
240}