Completed
Push — fix/normalize-www-in-site-url-... ( e67e76 )
by
unknown
13:13 queued 02:59
created

class.wpcom-json-api-list-comments-endpoint.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
class WPCOM_JSON_API_List_Comments_Walker extends Walker {
4
	public $tree_type = 'comment';
5
6
	public $db_fields = array(
7
		'parent' => 'comment_parent',
8
		'id'     => 'comment_ID'
9
	);
10
11
	public function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 ) {
12
		$output[] = $object->comment_ID;
13
	}
14
15
	/**
16
	 * Taken from WordPress's Walker_Comment::display_element()
17
	 *
18
	 * This function is designed to enhance Walker::display_element() to
19
	 * display children of higher nesting levels than selected inline on
20
	 * the highest depth level displayed. This prevents them being orphaned
21
	 * at the end of the comment list.
22
	 *
23
	 * Example: max_depth = 2, with 5 levels of nested content.
24
	 * 1
25
	 *  1.1
26
	 *    1.1.1
27
	 *    1.1.1.1
28
	 *    1.1.1.1.1
29
	 *    1.1.2
30
	 *    1.1.2.1
31
	 * 2
32
	 *  2.2
33
	 *
34
	 * @see Walker_Comment::display_element()
35
	 * @see Walker::display_element()
36
	 * @see wp_list_comments()
37
	 */
38
	public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
39
40
		if ( !$element )
41
			return;
42
43
		$id_field = $this->db_fields['id'];
44
		$id = $element->$id_field;
45
46
		parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
47
48
		// If we're at the max depth, and the current element still has children, loop over those and display them at this level
49
		// This is to prevent them being orphaned to the end of the list.
50
		if ( $max_depth <= $depth + 1 && isset( $children_elements[$id]) ) {
51
			foreach ( $children_elements[ $id ] as $child )
52
				$this->display_element( $child, $children_elements, $max_depth, $depth, $args, $output );
53
54
			unset( $children_elements[ $id ] );
55
		}
56
57
	}
58
}
59
60
// @todo permissions
61
class WPCOM_JSON_API_List_Comments_Endpoint extends WPCOM_JSON_API_Comment_Endpoint {
62
	public $response_format = array(
63
		'found'    => '(int) The total number of comments found that match the request (ignoring limits, offsets, and pagination).',
64
		'site_ID'  => '(int) The site ID',
65
		'comments' => '(array:comment) An array of comment objects.',
66
	);
67
68
	function __construct( $args ) {
69
		parent::__construct( $args );
70
		$this->query = array_merge( $this->query, array(
71
			'number'   => '(int=20) The number of comments to return.  Limit: 100. When using hierarchical=1, number refers to the number of top-level comments returned.',
72
			'offset'   => '(int=0) 0-indexed offset. Not available if using hierarchical=1.',
73
			'page'     => '(int) Return the Nth 1-indexed page of comments.  Takes precedence over the <code>offset</code> parameter. When using hierarchical=1, pagination is a bit different.  See the note on the number parameter.',
74
			'order'    => array(
75
				'DESC' => 'Return comments in descending order from newest to oldest.',
76
				'ASC'  => 'Return comments in ascending order from oldest to newest.',
77
			),
78
			'hierarchical' => array(
79
				'false' => '',
80
				'true' => '(BETA) Order the comment list hierarchically.',
81
			),
82
			'after'    => '(ISO 8601 datetime) Return comments dated on or after the specified datetime. Not available if using hierarchical=1.',
83
			'before'   => '(ISO 8601 datetime) Return comments dated on or before the specified datetime. Not available if using hierarchical=1.',
84
			'type'     => array(
85
				'any'       => 'Return all comments regardless of type.',
86
				'comment'   => 'Return only regular comments.',
87
				'trackback' => 'Return only trackbacks.',
88
				'pingback'  => 'Return only pingbacks.',
89
				'pings'     => 'Return both trackbacks and pingbacks.',
90
			),
91
			'status'   => array(
92
				'approved'   => 'Return only approved comments.',
93
				'unapproved' => 'Return only comments in the moderation queue.',
94
				'spam'       => 'Return only comments marked as spam.',
95
				'trash'      => 'Return only comments in the trash.',
96
				'all'        => 'Return comments of all statuses.',
97
			),
98
		) );
99
	}
100
101
	// /sites/%s/comments/            -> $blog_id
102
	// /sites/%s/posts/%d/replies/    -> $blog_id, $post_id
103
	// /sites/%s/comments/%d/replies/ -> $blog_id, $comment_id
104
	function callback( $path = '', $blog_id = 0, $object_id = 0 ) {
105
		$blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) );
0 ignored issues
show
Consider using a different name than the parameter $blog_id. This often makes code more readable.
Loading history...
106
		if ( is_wp_error( $blog_id ) ) {
107
			return $blog_id;
108
		}
109
110
		$args = $this->query_args();
111
112
		if ( $args['number'] < 1 ) {
113
			$args['number'] = 20;
114
		} elseif ( 100 < $args['number'] ) {
115
			return new WP_Error( 'invalid_number',  'The NUMBER parameter must be less than or equal to 100.', 400 );
116
		}
117
118
		if ( false !== strpos( $path, '/posts/' ) ) {
119
			// We're looking for comments of a particular post
120
			$post_id = $object_id;
121
			$comment_id = 0;
122
		} else {
123
			// We're looking for comments for the whole blog, or replies to a single comment
124
			$comment_id = $object_id;
125
			$post_id = 0;
126
		}
127
128
		// We can't efficiently get the number of replies to a single comment
129
		$count = false;
130
		$found = -1;
131
132
		if ( !$comment_id ) {
133
			// We can get comment counts for the whole site or for a single post, but only for certain queries
134
			if ( 'any' === $args['type'] && !isset( $args['after'] ) && !isset( $args['before'] ) ) {
135
				$count = wp_count_comments( $post_id );
136
			}
137
		}
138
139
		switch ( $args['status'] ) {
140
		case 'approved' :
141
			$status = 'approve';
142
			if ( $count ) {
143
				$found = $count->approved;
144
			}
145
			break;
146
		default :
147
			if ( !current_user_can( 'moderate_comments' ) ) {
148
				return new WP_Error( 'unauthorized', 'User cannot read non-approved comments', 403 );
149
			}
150
			if ( 'unapproved' === $args['status'] ) {
151
				$status = 'hold';
152
				$count_status = 'moderated';
153
			} elseif ( 'all' === $args['status'] ) {
154
				$status = 'all';
155
				$count_status = 'total_comments';
156
			} else {
157
				$status = $count_status = $args['status'];
158
			}
159
			if ( $count ) {
160
				$found = $count->$count_status;
161
			}
162
		}
163
164
		$query = array(
165
			'order'  => $args['order'],
166
			'type'   => 'any' === $args['type'] ? false : $args['type'],
167
			'status' => $status,
168
		);
169
170
		if ( isset( $args['page'] ) ) {
171
			if ( $args['page'] < 1 ) {
172
				$args['page'] = 1;
173
			}
174
		} else {
175
			if ( $args['offset'] < 0 ) {
176
				$args['offset'] = 0;
177
			}
178
		}
179
180
		if ( ! $args['hierarchical'] ) {
181
			$query['number'] = $args['number'];
182
183
			if ( isset( $args['page'] ) ) {
184
				$query['offset'] = ( $args['page'] - 1 ) * $args['number'];
185
			} else {
186
				$query['offset'] = $args['offset'];
187
			}
188
189
			$is_before = isset( $args['before_gmt'] );
190
			$is_after  = isset( $args['after_gmt'] );
191
192
			if ( $is_before || $is_after ) {
193
				$query['date_query'] = array(
194
					'column' => 'comment_date_gmt',
195
					'inclusive' => true,
196
				);
197
198
				if ( $is_before ) {
199
					$query['date_query']['before'] = $args['before_gmt'];
200
				}
201
202
				if ( $is_after ) {
203
					$query['date_query']['after'] = $args['after_gmt'];
204
				}
205
			}
206
		}
207
208
		if ( $post_id ) {
209
			$post = get_post( $post_id );
210
			if ( !$post || is_wp_error( $post ) ) {
211
				return new WP_Error( 'unknown_post', 'Unknown post', 404 );
212
			}
213
			$query['post_id'] = $post->ID;
214
			if ( $this->api->ends_with( $this->path, '/replies' ) ) {
215
				$query['parent'] = 0;
216
			}
217
		} elseif ( $comment_id ) {
218
			$comment = get_comment( $comment_id );
219
			if ( !$comment || is_wp_error( $comment ) ) {
220
				return new WP_Error( 'unknown_comment', 'Unknown comment', 404 );
221
			}
222
			$query['parent'] = $comment_id;
223
		}
224
225
		$comments = get_comments( $query );
226
227
		update_comment_cache( $comments );
228
229
		if ( $args['hierarchical'] ) {
230
			$walker = new WPCOM_JSON_API_List_Comments_Walker;
231
			$comment_ids = $walker->paged_walk( $comments, get_option( 'thread_comments_depth', -1 ), isset( $args['page'] ) ? $args['page'] : 1 , $args['number'] );
232
			if ( ! empty( $comment_ids ) ) {
233
				$comments = array_map( 'get_comment', $comment_ids );
234
			}
235
		}
236
237
		$return = array();
238
239
		foreach ( array_keys( $this->response_format ) as $key ) {
240
			switch ( $key ) {
241
			case 'found' :
242
				$return[ $key ] = (int) $found;
243
				break;
244
			case 'site_ID' :
245
				$return[ $key ] = (int) $blog_id;
246
				break;
247
			case 'comments' :
248
				$return_comments = array();
249
				if ( ! empty( $comments ) ) {
250
					foreach ( $comments as $comment ) {
251
						$the_comment = $this->get_comment( $comment->comment_ID, $args['context'] );
252
						if ( $the_comment && !is_wp_error( $the_comment ) ) {
253
							$return_comments[] = $the_comment;
254
						}
255
					}
256
				}
257
258
				if ( $return_comments ) {
259
					/** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */
260
					do_action( 'wpcom_json_api_objects', 'comments', count( $return_comments ) );
261
				}
262
263
				$return[ $key ] = $return_comments;
264
				break;
265
			}
266
		}
267
268
		return $return;
269
	}
270
}
271