PluginProbe
bbPress / 2.6.19
bbPress v2.6.19
2.6.19 2.6.18 2.6.17 trunk 2.0 2.0-beta-1 2.0-beta-2b 2.0-beta-3 2.0-beta-3b 2.0-rc-2 2.0-rc-3 2.0-rc-4 2.0-rc-5 2.0.1 2.0.2 2.0.3 2.1 2.1-beta-1 2.1-rc1 2.1-rc2 2.1-rc3 2.1-rc4 2.1.1 2.1.2 2.1.3 All 74 releases
bbpress / includes / common / xmlrpc.php

xmlrpc.php in bbPress 2.6.19, at includes/common/xmlrpc.php

284 lines 9.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * bbPress XML-RPC Functions.
5 *
6 * @package bbPress
7 * @subpackage Common
8 */
9
10 // Exit if accessed directly
11 defined( 'ABSPATH' ) || exit;
12
13 /**
14 * Validate an XML-RPC edit against bbPress posting rules.
15 *
16 * @since 2.6.17 bbPress (r7486)
17 * @since 2.6.19 bbPress (r7684) Validate publication and date changes.
18 *
19 * @param string $method XML-RPC method name.
20 * @param array $args XML-RPC method arguments.
21 */
22 function bbp_validate_xmlrpc_post( $method = '', $args = array() ) {
23 global $bbp_xmlrpc_error_post_id, $bbp_xmlrpc_error_post_type;
24
25 $bbp_xmlrpc_error_post_id = 0;
26 $bbp_xmlrpc_error_post_type = '';
27
28 // WordPress handles create permissions, but not bbPress's strict block list.
29 if ( 'wp.newPost' === $method ) {
30 if ( empty( $args[3] ) || ! is_array( $args[3] ) ) {
31 return;
32 }
33
34 $post_data = $args[3];
35 $post_type = isset( $post_data['post_type'] ) ? $post_data['post_type'] : '';
36 if ( ! in_array( $post_type, array( bbp_get_topic_post_type(), bbp_get_reply_post_type() ), true ) ) {
37 return;
38 }
39
40 $title = isset( $post_data['post_title'] ) ? wp_unslash( $post_data['post_title'] ) : '';
41 $content = isset( $post_data['post_content'] ) ? wp_unslash( $post_data['post_content'] ) : '';
42 if ( ! bbp_check_for_moderation( array(), bbp_get_current_user_id(), $title, $content, true ) ) {
43 $bbp_xmlrpc_error_post_type = $post_type;
44 }
45
46 return;
47 }
48
49 // mt.publishPost sets a post status without bbPress lifecycle handling
50 if ( 'mt.publishPost' === $method ) {
51 $post_id = ! empty( $args[0] ) ? (int) $args[0] : 0;
52 $post = get_post( $post_id );
53 $types = array( bbp_get_forum_post_type(), bbp_get_topic_post_type(), bbp_get_reply_post_type() );
54
55 if ( ! empty( $post ) && in_array( $post->post_type, $types, true ) && ( 'publish' !== $post->post_status ) ) {
56 $bbp_xmlrpc_error_post_id = $post_id;
57 }
58
59 return;
60 }
61
62 $is_restore = ( 'wp.restoreRevision' === $method );
63
64 // Validate an edit or resolve its revision back to a bbPress post
65 if ( 'wp.editPost' === $method ) {
66 if ( empty( $args[3] ) || empty( $args[4] ) || ! is_array( $args[4] ) ) {
67 return;
68 }
69
70 $post_id = (int) $args[3];
71 $post_data = $args[4];
72 } elseif ( $is_restore && ! empty( $args[3] ) ) {
73 $revision_id = (int) $args[3];
74 $revision = wp_get_post_revision( $revision_id );
75
76 if ( empty( $revision ) ) {
77 return;
78 }
79
80 $post_id = (int) $revision->post_parent;
81 $post_data = array(
82 'post_title' => $revision->post_title,
83 'post_content' => $revision->post_content,
84 );
85 } else {
86 return;
87 }
88
89 $post = get_post( $post_id );
90
91 if ( empty( $post ) ) {
92 return;
93 }
94
95 $post_type = $post->post_type;
96
97 if ( ! in_array( $post_type, array( bbp_get_forum_post_type(), bbp_get_topic_post_type(), bbp_get_reply_post_type() ), true ) ) {
98 return;
99 }
100
101 $post_parent = isset( $post_data['post_parent'] )
102 ? (int) $post_data['post_parent']
103 : (int) $post->post_parent;
104 $parent_changed = ( $post_parent !== (int) $post->post_parent );
105 $status_changed = isset( $post_data['post_status'] ) && ( $post_data['post_status'] !== $post->post_status );
106 $order_changed = isset( $post_data['menu_order'] ) && ( (int) $post_data['menu_order'] !== (int) $post->menu_order );
107 $invalid = false;
108 $is_forum_content = in_array( $post_type, array( bbp_get_topic_post_type(), bbp_get_reply_post_type() ), true );
109 $can_moderate = current_user_can( 'moderate', $post_id );
110
111 // Keep non-moderators from moving the edit window through XML-RPC dates
112 if ( $is_forum_content && ! $can_moderate && bbp_xmlrpc_post_date_changed( $post_data, $post ) ) {
113 $invalid = true;
114 }
115
116 // XML-RPC does not set the front-end query flags used by the topic and
117 // reply capability mappings to enforce the author edit window.
118 if ( $is_forum_content && ( bbp_get_current_user_id() === (int) $post->post_author ) && ! $can_moderate ) {
119 $post_date_gmt = ( '0000-00-00 00:00:00' === $post->post_date_gmt )
120 ? get_gmt_from_date( $post->post_date )
121 : $post->post_date_gmt;
122
123 if ( bbp_past_edit_lock( $post_date_gmt ) ) {
124 $invalid = true;
125 }
126 }
127
128 // Validate forum structure and visibility changes
129 if ( bbp_get_forum_post_type() === $post_type ) {
130 if ( ! $is_restore && $parent_changed && ! current_user_can( 'assign_moderators' ) ) {
131 $invalid = true;
132 }
133
134 if ( ! $is_restore && $status_changed && ! current_user_can( 'manage_forum_attributes', $post_id ) ) {
135 $invalid = true;
136 }
137
138 if ( ! $is_restore && $order_changed && ! current_user_can( 'assign_moderators' ) ) {
139 $invalid = true;
140 }
141
142 if ( $invalid ) {
143 $bbp_xmlrpc_error_post_id = $post_id;
144 }
145
146 return;
147 }
148
149 // Structural changes require bbPress lifecycle handlers to keep related metadata and counts synchronized
150 if ( ! $is_restore && ( $parent_changed || $status_changed || $order_changed ) ) {
151 $invalid = true;
152 }
153
154 // Validate topic forum access
155 if ( bbp_get_topic_post_type() === $post_type ) {
156 if ( empty( $post_parent ) || bbp_is_forum_category( $post_parent ) ) {
157 $invalid = true;
158 } elseif ( ! current_user_can( 'edit_forum', $post_parent ) && bbp_is_forum_closed( $post_parent ) ) {
159 $invalid = true;
160 } elseif ( ! current_user_can( 'read_forum', $post_parent ) ) {
161 $invalid = true;
162 }
163 }
164
165 // Validate reply topic and forum access
166 if ( bbp_get_reply_post_type() === $post_type ) {
167 $topic_id = bbp_get_reply_topic_id( $post_id );
168 $forum_id = bbp_get_topic_forum_id( $topic_id );
169
170 if ( ! current_user_can( 'read_topic', $topic_id ) || ! current_user_can( 'read_forum', $forum_id ) ) {
171 $invalid = true;
172 }
173 }
174
175 $title = isset( $post_data['post_title'] ) ? wp_unslash( $post_data['post_title'] ) : $post->post_title;
176 $content = isset( $post_data['post_content'] ) ? wp_unslash( $post_data['post_content'] ) : $post->post_content;
177
178 if ( empty( $content ) || ( ( bbp_get_topic_post_type() === $post_type ) && empty( $title ) ) || bbp_is_title_too_long( $title ) ) {
179 $invalid = true;
180 }
181
182 if ( ! bbp_check_for_moderation( array(), (int) $post->post_author, $title, $content, true ) ) {
183 $invalid = true;
184 }
185
186 // Revision restoration cannot change the post status to pending
187 if ( $is_restore && ! bbp_check_for_moderation( array(), (int) $post->post_author, $title, $content ) ) {
188 $invalid = true;
189 }
190
191 if ( $invalid ) {
192 $bbp_xmlrpc_error_post_id = $post_id;
193 }
194 }
195
196 /**
197 * Check whether XML-RPC date fields would change a post's publication date.
198 *
199 * Match the date conversion used by WordPress's wp.editPost method.
200 *
201 * @since 2.6.19 bbPress (r7684)
202 *
203 * @param array $post_data Submitted post fields.
204 * @param WP_Post $post Existing post.
205 * @return bool Whether the publication date would change.
206 */
207 function bbp_xmlrpc_post_date_changed( $post_data, $post ) {
208 if ( ! isset( $post_data['post_date'] ) && ! isset( $post_data['post_date_gmt'] ) ) {
209 return false;
210 }
211
212 if ( ! empty( $post_data['post_date_gmt'] ) && ( $post_data['post_date_gmt'] instanceof IXR_Date ) ) {
213 $iso_date = rtrim( $post_data['post_date_gmt']->getIso(), 'Z' ) . 'Z';
214 } elseif ( ! empty( $post_data['post_date'] ) && ( $post_data['post_date'] instanceof IXR_Date ) ) {
215 $iso_date = $post_data['post_date']->getIso();
216 } else {
217 return true;
218 }
219
220 $local = ! empty( $iso_date ) ? iso8601_to_datetime( $iso_date ) : false;
221 $gmt = ! empty( $iso_date ) ? iso8601_to_datetime( $iso_date, 'gmt' ) : false;
222 $post_date_gmt = ( '0000-00-00 00:00:00' === $post->post_date_gmt )
223 ? get_gmt_from_date( $post->post_date )
224 : $post->post_date_gmt;
225
226 return empty( $local ) || empty( $gmt ) || ( $post->post_date !== $local ) || ( $post_date_gmt !== $gmt );
227 }
228
229 /**
230 * Deny a post capability when an XML-RPC edit failed bbPress validation.
231 *
232 * @since 2.6.17 bbPress (r7486)
233 *
234 * @param array $caps Required capabilities.
235 * @param string $cap Requested capability.
236 * @param int $user_id User ID.
237 * @param array $args Capability arguments.
238 * @return array Required capabilities.
239 */
240 function bbp_map_xmlrpc_meta_caps( $caps = array(), $cap = '', $user_id = 0, $args = array() ) {
241 global $bbp_xmlrpc_error_post_id, $bbp_xmlrpc_error_post_type;
242
243 $edit_caps = array( 'edit_post', 'edit_topic', 'edit_reply' );
244
245 if ( ! empty( $bbp_xmlrpc_error_post_id ) && in_array( $cap, $edit_caps, true ) && ! empty( $args[0] ) && ( (int) $args[0] === $bbp_xmlrpc_error_post_id ) ) {
246 $caps[] = 'do_not_allow';
247 }
248 if ( ( ( bbp_get_topic_post_type() === $bbp_xmlrpc_error_post_type ) && ( 'edit_topics' === $cap ) ) || ( ( bbp_get_reply_post_type() === $bbp_xmlrpc_error_post_type ) && ( 'edit_replies' === $cap ) ) ) {
249 $caps[] = 'do_not_allow';
250 }
251
252 return $caps;
253 }
254
255 /**
256 * Apply bbPress moderation to XML-RPC post data.
257 *
258 * @since 2.6.17 bbPress (r7486)
259 *
260 * @param array $post_data Parsed post data.
261 * @return array Parsed post data.
262 */
263 function bbp_xmlrpc_wp_insert_post_data( $post_data = array() ) {
264 $post_id = ! empty( $post_data['ID'] ) ? (int) $post_data['ID'] : 0;
265 $post_type = isset( $post_data['post_type'] ) ? $post_data['post_type'] : '';
266
267 if ( empty( $post_id ) || ! in_array( $post_type, array( bbp_get_topic_post_type(), bbp_get_reply_post_type() ), true ) ) {
268 return $post_data;
269 }
270
271 $title = isset( $post_data['post_title'] ) ? wp_unslash( $post_data['post_title'] ) : '';
272 $content = isset( $post_data['post_content'] ) ? wp_unslash( $post_data['post_content'] ) : '';
273 $author_id = isset( $post_data['post_author'] ) ? (int) $post_data['post_author'] : 0;
274 $is_public = ( bbp_get_topic_post_type() === $post_type )
275 ? bbp_is_topic_public( $post_id )
276 : bbp_is_reply_public( $post_id );
277
278 if ( $is_public && ! bbp_check_for_moderation( array(), $author_id, $title, $content ) ) {
279 $post_data['post_status'] = bbp_get_pending_status_id();
280 }
281
282 return $post_data;
283 }
284