PluginProbe
Friends / 2.7.5
Friends v2.7.5
4.3.2 4.3.1 4.3.0 4.2.2 4.2.1 4.2.0 4.1.0 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.8.0 2.8.1 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.0 2.9.1 All 88 releases
friends / includes / class-messages.php

class-messages.php in Friends 2.7.5, at includes/class-messages.php

559 lines 15.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Friends Messages
4 *
5 * This contains the functions for Messages.
6 *
7 * @package Friends
8 */
9
10 namespace Friends;
11
12 /**
13 * This is the class for the Messages part of the Friends Plugin.
14 *
15 * @since 0.21
16 *
17 * @package Friends
18 * @author Alex Kirk
19 */
20 class Messages {
21 const CPT = 'friend_message';
22
23 /**
24 * Contains a reference to the Friends class.
25 *
26 * @var Friends
27 */
28 private $friends;
29
30 /**
31 * Constructor
32 *
33 * @param Friends $friends A reference to the Friends object.
34 */
35 public function __construct( Friends $friends ) {
36 $this->friends = $friends;
37 $this->register_hooks();
38 }
39
40 /**
41 * Register the WordPress hooks
42 */
43 private function register_hooks() {
44 add_action( 'init', array( $this, 'register_custom_post_type' ) );
45 add_filter( 'friends_unread_count', array( $this, 'friends_unread_messages_count' ) );
46 add_action( 'friends_own_site_menu_top', array( $this, 'friends_add_menu_unread_messages' ) );
47 add_action( 'wp_ajax_friends-mark-read', array( $this, 'mark_message_read' ) );
48 add_action( 'rest_api_init', array( $this, 'add_rest_routes' ) );
49 add_action( 'friends_author_header', array( $this, 'friends_author_header' ), 10, 2 );
50 add_action( 'friends_after_header', array( $this, 'friends_display_messages' ), 10, 2 );
51 add_action( 'friends_after_header', array( $this, 'friends_message_form' ), 11, 2 );
52 add_filter( 'template_redirect', array( $this, 'handle_message_send' ), 10, 2 );
53 }
54
55
56 /**
57 * Registers the custom post type
58 */
59 public function register_custom_post_type() {
60 $labels = array(
61 'name' => __( 'Friend Messages', 'friends' ),
62 'singular_name' => __( 'Friend Message', 'friends' ),
63 'add_new' => _x( 'Add New', 'cached friend post', 'friends' ),
64 'add_new_item' => __( 'Add New Friend Message', 'friends' ),
65 'edit_item' => __( 'Edit Friend Message', 'friends' ),
66 'new_item' => __( 'New Friend Message', 'friends' ),
67 'all_items' => __( 'All Friend Messages', 'friends' ),
68 'view_item' => __( 'View Friend Message', 'friends' ),
69 'search_items' => __( 'Search Friend Messages', 'friends' ),
70 'not_found' => __( 'No Friend Messages found', 'friends' ),
71 'not_found_in_trash' => __( 'No Friend Messages found in the Trash', 'friends' ),
72 'parent_item_colon' => '',
73 'menu_name' => __( 'Friend Messages', 'friends' ),
74 );
75
76 $args = array(
77 'labels' => $labels,
78 'description' => "A friend's message",
79 'publicly_queryable' => Friends::has_required_privileges(),
80 'show_ui' => true,
81 'show_in_menu' => apply_filters( 'friends_show_cached_posts', false ),
82 'show_in_nav_menus' => false,
83 'show_in_admin_bar' => false,
84 'show_in_rest' => Friends::has_required_privileges(),
85 'exclude_from_search' => true,
86 'public' => false,
87 'delete_with_user' => true,
88 'menu_position' => 6,
89 'menu_icon' => 'dashicons-admin-comments',
90 'supports' => array( 'title', 'editor', 'author', 'revisions' ),
91 'taxonomies' => array( 'friend-reaction-' . get_current_user_id() ),
92 'has_archive' => true,
93 'rewrite' => false,
94 );
95
96 register_post_type( self::CPT, $args );
97
98 register_post_status(
99 'friends_unread',
100 array(
101 'label' => _x( 'Unread', 'message', 'friends' ),
102 'public' => false,
103 'exclude_from_search' => true,
104 'show_in_admin_all_list' => false,
105 'show_in_admin_status_list' => false,
106 // translators: %s; number of unread messages.
107 'label_count' => _n_noop( 'Unread (%s)', 'Unread (%s)', 'friends' ),
108 )
109 );
110
111 register_post_status(
112 'friends_read',
113 array(
114 'label' => _x( 'Read', 'message', 'friends' ),
115 'public' => false,
116 'exclude_from_search' => true,
117 'show_in_admin_all_list' => false,
118 'show_in_admin_status_list' => false,
119 // translators: %s; number of read messages.
120 'label_count' => _n_noop( 'Read (%s)', 'Read (%s)', 'friends' ),
121 )
122 );
123
124 }
125
126 /**
127 * Add the REST API to send and receive friend requests
128 */
129 public function add_rest_routes() {
130 register_rest_route(
131 REST::PREFIX,
132 'message',
133 array(
134 'methods' => 'POST',
135 'callback' => array( $this, 'rest_receive_message' ),
136 'permission_callback' => Friends::authenticated_for_posts(),
137 )
138 );
139 }
140
141 /**
142 * Receive a message via REST
143 *
144 * @param \WP_REST_Request $request The incoming request.
145 * @return array The array to be returned via the REST API.
146 */
147 public function rest_receive_message( \WP_REST_Request $request ) {
148 $tokens = explode( '-', $request->get_param( 'auth' ) );
149 $user_id = $this->friends->access_control->verify_token( $tokens[0], isset( $tokens[1] ) ? $tokens[1] : null, isset( $tokens[2] ) ? $tokens[2] : null );
150 if ( ! $user_id ) {
151 return new \WP_Error(
152 'friends_request_failed',
153 __( 'Could not respond to the request.', 'friends' ),
154 array(
155 'status' => 403,
156 )
157 );
158 }
159
160 $friend_user = new User( $user_id );
161 if ( ! $friend_user->has_cap( self::get_minimum_cap() ) ) {
162 return new \WP_Error(
163 'friends_request_failed',
164 __( 'Could not respond to the request.', 'friends' ),
165 array(
166 'status' => 403,
167 )
168 );
169 }
170
171 $subject = wp_unslash( $request->get_param( 'subject' ) );
172 $message = wp_unslash( $request->get_param( 'message' ) );
173 $this->add_message_to_post( $friend_user, $friend_user, $subject, $message, true );
174
175 do_action( 'notify_friend_message_received', $friend_user, $message, $subject );
176
177 return array(
178 'status' => 'message-received',
179 );
180 }
181
182 /**
183 * Adds a message to friends_message post.
184 *
185 * @param \WP_User $sender The sender.
186 * @param User $friend_user The friend user to which this should be associated.
187 * @param string $subject The subject.
188 * @param string $message The message.
189 *
190 * @return int The post ID.
191 */
192 private function add_message_to_post( \WP_User $sender, User $friend_user, $subject, $message ) {
193 $existing_message = new \WP_Query(
194 array(
195 'post_type' => self::CPT,
196 'author' => $friend_user->ID,
197 'title' => $subject,
198 'post_status' => array( 'friends_read', 'friends_unread' ),
199 )
200 );
201 $mark_unread = $sender->ID === $friend_user->ID;
202
203 $content = '';
204 $content .= '<!-- wp:friends/message {"sender":' . $sender->ID . ',"date":' . time() . '} -->' . PHP_EOL;
205 $content .= '<div class="wp-block-friends-message">';
206 $content .= '<span class="date">' . esc_html( gmdate( 'Y-m-d H:i:s' ) ) . '</span> ';
207 $content .= '<strong>' . esc_html( $sender->display_name ) . '</strong>: ';
208 if ( false === strpos( $message, '<!-- wp:' ) ) {
209 $content .= '<!-- wp:paragraph -->' . PHP_EOL . '<p>' . wp_kses_post( $message );
210 $content .= '</p>' . PHP_EOL;
211 $content .= '<!-- /wp:paragraph -->';
212 } else {
213 $content .= wp_kses_post( $message );
214 }
215 $content .= '</div>';
216 $content .= '<!-- /wp:friends/message -->';
217
218 if ( $existing_message->have_posts() ) {
219 $post = $existing_message->next_post();
220 $post_id = $post->ID;
221 wp_update_post(
222 array(
223 'ID' => $post->ID,
224 'post_content' => $post->post_content . PHP_EOL . $content,
225 'post_status' => $mark_unread ? 'friends_unread' : 'friends_read',
226 )
227 );
228 } else {
229 $post_id = $friend_user->insert_post(
230 array(
231 'post_type' => self::CPT,
232 'post_title' => $subject,
233 'post_content' => $content,
234 'post_status' => $mark_unread ? 'friends_unread' : 'friends_read',
235 )
236 );
237 }
238
239 return $post_id;
240 }
241
242 /**
243 * Add the unread messages to the total.
244 *
245 * @param int $unread The unread count.
246 *
247 * @return int Unread count + unread messages.
248 */
249 public function friends_unread_messages_count( $unread ) {
250 $unread_messages = new \WP_Query(
251 array(
252 'post_type' => self::CPT,
253 'post_status' => 'friends_unread',
254 )
255 );
256 return $unread + $unread_messages->post_count;
257 }
258
259 /**
260 * Add entries to the menu for unread messages.
261 *
262 * @param \WP_Menu $wp_menu The wp menu.
263 */
264 public function friends_add_menu_unread_messages( $wp_menu ) {
265 global $post;
266 $unread_messages = new \WP_Query(
267 array(
268 'post_type' => self::CPT,
269 'post_status' => 'friends_unread',
270 )
271 );
272
273 while ( $unread_messages->have_posts() ) {
274 $unread_messages->the_post();
275 $friend_user = User::get_post_author( $post );
276 $wp_menu->add_menu(
277 array(
278 'id' => 'friend-message-' . $friend_user->ID,
279 'parent' => 'friends-menu',
280 // translators: %s is the number of open friend requests.
281 'title' => '<span style="border-left: 2px solid #d63638; padding-left: .5em">' . esc_html( sprintf( __( 'New message from %s', 'friends' ), $friend_user->display_name ) ) . '</span>',
282 'href' => $friend_user->get_local_friends_page_url(),
283 )
284 );
285 }
286 }
287
288 /**
289 * Ajax function to mark a message as read.
290 *
291 * @return \WP_Error The wp error.
292 */
293 public function mark_message_read() {
294 check_ajax_referer( 'friends-mark-read' );
295
296 if ( ! is_user_logged_in() ) {
297 return new \WP_Error( 'unauthorized', 'You are not authorized to send a reaction.' );
298 }
299
300 if ( ! isset( $_POST['post_id'] ) ) {
301 wp_send_json_error(
302 array(
303 'result' => false,
304 )
305 );
306 }
307 if ( ! is_numeric( $_POST['post_id'] ) || $_POST['post_id'] <= 0 ) {
308 wp_send_json_error(
309 array(
310 'result' => false,
311 )
312 );
313 }
314
315 $post_id = intval( $_POST['post_id'] );
316 wp_update_post(
317 array(
318 'ID' => $post_id,
319 'post_status' => 'friends_read',
320 )
321 );
322
323 do_action( 'friends_message_read', $post_id );
324
325 wp_send_json_success(
326 array(
327 'result' => true,
328 )
329 );
330 }
331
332 /**
333 * Adds the friend requests to the unread count.
334 *
335 * @param int $unread The unread count.
336 *
337 * @return int Unread count + friend requests.
338 */
339 public function friends_unread_friend_request_count( $unread ) {
340 $friend_requests = User_Query::all_friend_requests();
341 return $unread + $friend_requests->get_total();
342 }
343
344 /**
345 * Extend the author header.
346 *
347 * @param User $friend_user The friend user.
348 * @param array $args The arguments.
349 */
350 public function friends_author_header( User $friend_user, $args ) {
351 if ( $friend_user->has_cap( self::get_minimum_cap() ) ) {
352 Friends::template_loader()->get_template_part(
353 'frontend/messages/author-header',
354 null,
355 $args
356 );
357
358 }
359 }
360
361 /**
362 * Display received messages by the friend user.
363 *
364 * @param array $args The arguments.
365 */
366 public function friends_display_messages( $args ) {
367 if ( ! isset( $args['friend_user'] ) || ! $args['friend_user'] ) {
368 return;
369 }
370
371 if ( $args['friend_user']->has_cap( self::get_minimum_cap() ) ) {
372 $args['existing_messages'] = new \WP_Query(
373 array(
374 'post_type' => self::CPT,
375 'author' => $args['friend_user']->ID,
376 'post_status' => array( 'friends_read', 'friends_unread' ),
377 )
378 );
379
380 if ( ! $args['existing_messages']->have_posts() ) {
381 return;
382 }
383
384 Friends::template_loader()->get_template_part(
385 'frontend/messages/friend',
386 null,
387 $args
388 );
389
390 }
391 }
392
393 /**
394 * Embed the message form for the friend user.
395 *
396 * @param array $args The arguments.
397 */
398 public function friends_message_form( $args ) {
399 if ( ! isset( $args['friend_user'] ) || ! $args['friend_user'] ) {
400 return;
401 }
402
403 if ( $args['friend_user']->has_cap( self::get_minimum_cap() ) ) {
404 Friends::template_loader()->get_template_part(
405 'frontend/messages/message-form',
406 null,
407 $args
408 );
409
410 }
411 }
412
413 /**
414 * Gets the minimum capability necessary to use messages.
415 *
416 * @return string The minimum capability.
417 */
418 public static function get_minimum_cap() {
419 return apply_filters( 'friends_message_minimum_cap', 'friend' );
420 }
421
422 /**
423 * Sends a message to a friend.
424 *
425 * @param User $friend_user The friend user.
426 * @param string $message The message.
427 * @param string $subject The subject.
428 *
429 * @return \WP_Error|int An error or the message post id.
430 */
431 public function send_message( User $friend_user, $message, $subject = null ) {
432 if ( ! $friend_user->has_cap( self::get_minimum_cap() ) ) {
433 return new \WP_Error( 'not-a-friend', __( 'You cannot send messages to this user.', 'friends' ) );
434 }
435 if ( ! trim( $message ) ) {
436 return new \WP_Error( 'empty-message', __( 'You cannot send empty messages.', 'friends' ) );
437 }
438
439 if ( empty( $subject ) ) {
440 $subject = sprintf(
441 // translators: %1$s is a date, %2$s is a time.
442 __( 'Conversation started on %1$s at %2$s', 'friends' ),
443 gmdate( 'Y-m-d' ),
444 gmdate( 'H:i:s' )
445 );
446 }
447
448 $post_id = $this->add_message_to_post( wp_get_current_user(), $friend_user, $subject, $message );
449
450 $body = array(
451 'subject' => $subject,
452 'message' => $message,
453 'auth' => $friend_user->get_friend_auth(),
454 );
455
456 $response = wp_safe_remote_post(
457 $friend_user->get_rest_url() . '/message',
458 array(
459 'body' => $body,
460 'timeout' => 20,
461 'redirection' => 5,
462 )
463 );
464
465 if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
466 // TODO find a way to message the user.
467 return new \WP_Error( 'invalid-response', __( 'We received an unexpected response to our message.', 'friends' ) );
468 }
469
470 return $post_id;
471 }
472
473 /**
474 * Delete a conversation
475 *
476 * @param User $friend_user The friend user.
477 * @param string $subject The subject.
478 *
479 * @return \WP_Error|\WP_Post|bool The post or false.
480 */
481 public function delete_conversation( User $friend_user, $subject ) {
482 if ( ! $friend_user->has_cap( self::get_minimum_cap() ) ) {
483 return new \WP_Error( 'not-a-friend', __( 'You cannot delete converations.', 'friends' ) );
484 }
485
486 $existing_message = new \WP_Query(
487 array(
488 'post_type' => self::CPT,
489 'author' => $friend_user->ID,
490 'title' => $subject,
491 'post_status' => array( 'friends_read', 'friends_unread' ),
492 )
493 );
494
495 if ( $existing_message->have_posts() ) {
496 $post = $existing_message->next_post();
497 return wp_trash_post( $post->ID );
498 }
499
500 return false;
501 }
502
503 /**
504 * Handle the message form.
505 */
506 public function handle_message_send() {
507 if ( ! isset( $_REQUEST['friends_message_recipient'] ) ) {
508 return;
509 }
510
511 if ( isset( $_REQUEST['friends_message_delete_conversation'] ) ) {
512 return $this->handle_conversation_delete();
513 }
514
515 if ( ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'friends_send_message' ) ) {
516 wp_die( esc_html( __( 'Error - unable to verify nonce, please try again.', 'friends' ) ) );
517 }
518
519 $friend_user = new User( $_REQUEST['friends_message_recipient'] );
520
521 $subject = wp_unslash( $_REQUEST['friends_message_subject'] );
522 $message = wp_unslash( $_REQUEST['friends_message_message'] );
523
524 $error = $this->send_message( $friend_user, $message, $subject );
525
526 if ( is_wp_error( $error ) ) {
527 wp_die( esc_html( $error->get_error_message() ) );
528 }
529
530 wp_safe_redirect( $friend_user->get_local_friends_page_url() );
531 exit;
532 }
533
534 /**
535 * Handle the deletion of the conversation.
536 */
537 public function handle_conversation_delete() {
538 if ( ! isset( $_REQUEST['friends_message_delete_conversation'] ) ) {
539 return;
540 }
541
542 if ( ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'friends_send_message' ) ) {
543 wp_die( esc_html( __( 'Error - unable to verify nonce, please try again.', 'friends' ) ) );
544 }
545
546 $friend_user = new User( $_REQUEST['friends_message_recipient'] );
547
548 $subject = wp_unslash( $_REQUEST['friends_message_subject'] );
549 $error = $this->delete_conversation( $friend_user, $subject );
550
551 if ( is_wp_error( $error ) ) {
552 wp_die( esc_html( $error->get_error_message() ) );
553 }
554
555 wp_safe_redirect( $friend_user->get_local_friends_page_url() );
556 exit;
557 }
558 }
559