PluginProbe
Friends / 2.7.6
Friends v2.7.6
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.6, at includes/class-messages.php

561 lines 15.8 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 $args['blocks-everywhere'] = get_user_option( 'friends_blocks_everywhere' );
404
405 if ( $args['friend_user']->has_cap( self::get_minimum_cap() ) ) {
406 Friends::template_loader()->get_template_part(
407 'frontend/messages/message-form',
408 null,
409 $args
410 );
411
412 }
413 }
414
415 /**
416 * Gets the minimum capability necessary to use messages.
417 *
418 * @return string The minimum capability.
419 */
420 public static function get_minimum_cap() {
421 return apply_filters( 'friends_message_minimum_cap', 'friend' );
422 }
423
424 /**
425 * Sends a message to a friend.
426 *
427 * @param User $friend_user The friend user.
428 * @param string $message The message.
429 * @param string $subject The subject.
430 *
431 * @return \WP_Error|int An error or the message post id.
432 */
433 public function send_message( User $friend_user, $message, $subject = null ) {
434 if ( ! $friend_user->has_cap( self::get_minimum_cap() ) ) {
435 return new \WP_Error( 'not-a-friend', __( 'You cannot send messages to this user.', 'friends' ) );
436 }
437 if ( ! trim( $message ) ) {
438 return new \WP_Error( 'empty-message', __( 'You cannot send empty messages.', 'friends' ) );
439 }
440
441 if ( empty( $subject ) ) {
442 $subject = sprintf(
443 // translators: %1$s is a date, %2$s is a time.
444 __( 'Conversation started on %1$s at %2$s', 'friends' ),
445 gmdate( 'Y-m-d' ),
446 gmdate( 'H:i:s' )
447 );
448 }
449
450 $post_id = $this->add_message_to_post( wp_get_current_user(), $friend_user, $subject, $message );
451
452 $body = array(
453 'subject' => $subject,
454 'message' => $message,
455 'auth' => $friend_user->get_friend_auth(),
456 );
457
458 $response = wp_safe_remote_post(
459 $friend_user->get_rest_url() . '/message',
460 array(
461 'body' => $body,
462 'timeout' => 20,
463 'redirection' => 5,
464 )
465 );
466
467 if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
468 // TODO find a way to message the user.
469 return new \WP_Error( 'invalid-response', __( 'We received an unexpected response to our message.', 'friends' ) );
470 }
471
472 return $post_id;
473 }
474
475 /**
476 * Delete a conversation
477 *
478 * @param User $friend_user The friend user.
479 * @param string $subject The subject.
480 *
481 * @return \WP_Error|\WP_Post|bool The post or false.
482 */
483 public function delete_conversation( User $friend_user, $subject ) {
484 if ( ! $friend_user->has_cap( self::get_minimum_cap() ) ) {
485 return new \WP_Error( 'not-a-friend', __( 'You cannot delete converations.', 'friends' ) );
486 }
487
488 $existing_message = new \WP_Query(
489 array(
490 'post_type' => self::CPT,
491 'author' => $friend_user->ID,
492 'title' => $subject,
493 'post_status' => array( 'friends_read', 'friends_unread' ),
494 )
495 );
496
497 if ( $existing_message->have_posts() ) {
498 $post = $existing_message->next_post();
499 return wp_trash_post( $post->ID );
500 }
501
502 return false;
503 }
504
505 /**
506 * Handle the message form.
507 */
508 public function handle_message_send() {
509 if ( ! isset( $_REQUEST['friends_message_recipient'] ) ) {
510 return;
511 }
512
513 if ( isset( $_REQUEST['friends_message_delete_conversation'] ) ) {
514 return $this->handle_conversation_delete();
515 }
516
517 if ( ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'friends_send_message' ) ) {
518 wp_die( esc_html( __( 'Error - unable to verify nonce, please try again.', 'friends' ) ) );
519 }
520
521 $friend_user = new User( $_REQUEST['friends_message_recipient'] );
522
523 $subject = wp_unslash( $_REQUEST['friends_message_subject'] );
524 $message = wp_unslash( $_REQUEST['friends_message_message'] );
525
526 $error = $this->send_message( $friend_user, $message, $subject );
527
528 if ( is_wp_error( $error ) ) {
529 wp_die( esc_html( $error->get_error_message() ) );
530 }
531
532 wp_safe_redirect( $friend_user->get_local_friends_page_url() );
533 exit;
534 }
535
536 /**
537 * Handle the deletion of the conversation.
538 */
539 public function handle_conversation_delete() {
540 if ( ! isset( $_REQUEST['friends_message_delete_conversation'] ) ) {
541 return;
542 }
543
544 if ( ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'friends_send_message' ) ) {
545 wp_die( esc_html( __( 'Error - unable to verify nonce, please try again.', 'friends' ) ) );
546 }
547
548 $friend_user = new User( $_REQUEST['friends_message_recipient'] );
549
550 $subject = wp_unslash( $_REQUEST['friends_message_subject'] );
551 $error = $this->delete_conversation( $friend_user, $subject );
552
553 if ( is_wp_error( $error ) ) {
554 wp_die( esc_html( $error->get_error_message() ) );
555 }
556
557 wp_safe_redirect( $friend_user->get_local_friends_page_url() );
558 exit;
559 }
560 }
561