JezK
Edit File: KirkiCommentsRest.php
<?php /** * Collection controller * * @package kirki */ namespace Kirki\API\KirkiComments; if (!defined('ABSPATH')) { exit; // Exit if accessed directly. } use Kirki\Ajax\Collaboration\Collaboration; use Kirki\HelperFunctions; use WP_Error; use WP_REST_Controller; use WP_REST_Server; /** * ContentManagerRest * * @deprecated * @see \Kirki\App\Http\Controllers\Api\CollaborationCommentController */ class KirkiCommentsRest extends WP_REST_Controller { /** * Initialize the media class * * @return void */ public function __construct() { $this->namespace = 'kirki/v1'; $this->rest_base = 'kirki-comments'; } /** * Register register * * @return void */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base . '/all', array( array( 'methods' => 'GET', 'callback' => array($this, 'get_all_comments'), 'permission_callback' => array($this, 'get_item_permissions_check'), 'args' => $this->get_endpoint_args_for_item_schema(WP_REST_Server::READABLE), ), 'schema' => array($this, 'get_item_schema'), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/create', array( array( 'methods' => 'POST', 'callback' => array($this, 'create_comment'), 'permission_callback' => array($this, 'create_item_permissions_check'), 'args' => $this->get_endpoint_args_for_item_schema(WP_REST_Server::CREATABLE), ), 'schema' => array($this, 'get_item_schema'), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/resolve', array( array( 'methods' => 'POST', 'callback' => array($this, 'resolve_comment'), 'permission_callback' => array($this, 'create_item_permissions_check'), 'args' => $this->get_endpoint_args_for_item_schema(WP_REST_Server::CREATABLE), ), 'schema' => array($this, 'get_item_schema'), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/all-users', array( array( 'methods' => 'GET', 'callback' => array($this, 'get_all_users'), 'permission_callback' => array($this, 'get_item_permissions_check'), 'args' => array( 'query' => array( 'description' => 'Search query for user display name.', 'type' => 'string', 'required' => false, ), ), ), 'schema' => null, ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/read', array( array( 'methods' => 'POST', 'callback' => array($this, 'read_comment'), 'permission_callback' => array($this, 'create_item_permissions_check'), 'args' => $this->get_endpoint_args_for_item_schema(WP_REST_Server::CREATABLE), ), 'schema' => array($this, 'get_item_schema'), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/unread', array( array( 'methods' => 'POST', 'callback' => array($this, 'unread_comment'), 'permission_callback' => array($this, 'create_item_permissions_check'), 'args' => $this->get_endpoint_args_for_item_schema(WP_REST_Server::CREATABLE), ), 'schema' => array($this, 'get_item_schema'), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/delete', array( array( 'methods' => 'POST', 'callback' => array($this, 'delete_comment'), 'permission_callback' => array($this, 'create_item_permissions_check'), 'args' => $this->get_endpoint_args_for_item_schema(WP_REST_Server::CREATABLE), ), 'schema' => array($this, 'get_item_schema'), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/read-all', array( array( 'methods' => 'POST', 'callback' => array($this, 'read_all_comments'), 'permission_callback' => array($this, 'create_item_permissions_check'), 'args' => $this->get_endpoint_args_for_item_schema(WP_REST_Server::CREATABLE), ), 'schema' => array($this, 'get_item_schema'), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/resolve-all', array( array( 'methods' => 'POST', 'callback' => array($this, 'resolve_all_comments'), 'permission_callback' => array($this, 'create_item_permissions_check'), 'args' => $this->get_endpoint_args_for_item_schema(WP_REST_Server::CREATABLE), ), 'schema' => array($this, 'get_item_schema'), ) ); } public function read_all_comments($request) { $post_id = HelperFunctions::sanitize_text(isset($request['post_id']) ? $request['post_id'] : ''); $user_id = get_current_user_id(); global $wpdb; $seen_table_name = $wpdb->prefix . KIRKI_COMMENTS_TABLE . '_seen'; $comments_table = $wpdb->prefix . KIRKI_COMMENTS_TABLE; $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO $seen_table_name (user_id, comment_id) SELECT %d, id FROM $comments_table WHERE post_id = %d AND parent_id = 0", $user_id, $post_id ) ); return rest_ensure_response( array( 'status' => 'success', 'message' => __('All comments marked as read.', 'kirki'), ) ); } public function resolve_all_comments($request) { $post_id = HelperFunctions::sanitize_text(isset($request['post_id']) ? $request['post_id'] : ''); $session_id = HelperFunctions::sanitize_text(isset($request['session_id']) ? $request['session_id'] : ''); $status = 2; global $wpdb; $table_name = $wpdb->prefix . KIRKI_COMMENTS_TABLE; $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET status = %d WHERE post_id = %d AND parent_id = 0", $status, $post_id ) ); $data = array( 'type' => 'COLLABORATION_UPDATE_ALL_KIRKI_COMMENT', 'payload' => array('data' => array('status' => '' . $status)), ); Collaboration::save_action_to_db('post', $post_id, $data, 1, $session_id); return rest_ensure_response( array( 'status' => 'success', 'message' => __('All comments marked as resolved.', 'kirki'), ) ); } public function resolve_comment($request) { $comment_id = intval(HelperFunctions::sanitize_text(isset($request['id']) ? $request['id'] : '0')); $post_id = HelperFunctions::sanitize_text(isset($request['post_id']) ? $request['post_id'] : ''); $status = intval(HelperFunctions::sanitize_text(isset($request['status']) ? $request['status'] : '1')); $session_id = HelperFunctions::sanitize_text(isset($request['session_id']) ? $request['session_id'] : ''); global $wpdb; $table_name = $wpdb->prefix . KIRKI_COMMENTS_TABLE; $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET status = %d WHERE id = %d", $status, $comment_id ) ); $data = array( 'type' => 'COLLABORATION_UPDATE_KIRKI_COMMENT', 'payload' => array( 'data' => array('status' => '' . $status), 'id' => '' . $comment_id, ), ); Collaboration::save_action_to_db('post', $post_id, $data, 1, $session_id); return rest_ensure_response($this->get_single_comment($comment_id)); } public function read_comment($request) { $comment_id = intval(HelperFunctions::sanitize_text(isset($request['id']) ? $request['id'] : '0')); $user_id = get_current_user_id(); global $wpdb; $seen_table_name = $wpdb->prefix . KIRKI_COMMENTS_TABLE . '_seen'; $wpdb->query( $wpdb->prepare( "INSERT INTO $seen_table_name (user_id, comment_id) VALUES ( %d, %d )", $user_id, $comment_id ) ); return rest_ensure_response($this->get_single_comment($comment_id)); } public function unread_comment($request) { $comment_id = intval(HelperFunctions::sanitize_text(isset($request['id']) ? $request['id'] : '0')); $user_id = get_current_user_id(); global $wpdb; $seen_table_name = $wpdb->prefix . KIRKI_COMMENTS_TABLE . '_seen'; $wpdb->query( $wpdb->prepare( "DELETE FROM $seen_table_name WHERE comment_id = %d AND user_id = %d", $comment_id, $user_id ) ); return rest_ensure_response($this->get_single_comment($comment_id)); } public function delete_comment($request) { $comment_id = intval(HelperFunctions::sanitize_text(isset($request['id']) ? $request['id'] : '0')); $post_id = HelperFunctions::sanitize_text(isset($request['post_id']) ? $request['post_id'] : ''); $session_id = HelperFunctions::sanitize_text(isset($request['session_id']) ? $request['session_id'] : ''); $user = wp_get_current_user(); $comment = $this->get_single_comment($comment_id); $allowed_roles = array('editor', 'administrator'); if ($comment['user_id'] == $user->ID || array_intersect($allowed_roles, $user->roles)) { global $wpdb; $table_name = $wpdb->prefix . KIRKI_COMMENTS_TABLE; $wpdb->query( $wpdb->prepare( "DELETE FROM $table_name WHERE id = %d OR parent_id = %d", $comment_id, $comment_id ) ); $data = array( 'type' => 'COLLABORATION_DELETE_KIRKI_COMMENT', 'payload' => array('id' => '' . $comment_id), ); Collaboration::save_action_to_db('post', $post_id, $data, 1, $session_id); return rest_ensure_response( array( 'status' => 'success', 'message' => __('Comment deleted successfully.', 'kirki'), ) ); } else { return rest_ensure_response( array( 'status' => 'error', 'message' => __('You do not have permission to delete this comment.', 'kirki'), ) ); } } public function get_all_users($request) { $roles = HelperFunctions::get_all_user_roles_by_access_levels( array( KIRKI_ACCESS_LEVELS['FULL_ACCESS'], KIRKI_ACCESS_LEVELS['CONTENT_ACCESS'], KIRKI_ACCESS_LEVELS['VIEW_ACCESS'], ) ); $query = isset($request['query']) ? sanitize_text_field($request['query']) : ''; $per_page = HelperFunctions::sanitize_text(isset($request['per_page']) ? $request['per_page'] : 20); $args = array( 'role__in' => $roles, 'orderby' => 'display_name', 'order' => 'ASC', 'number' => $per_page, 'search' => '*' . esc_attr($query) . '*', 'search_columns' => array('user_login', 'user_nicename', 'display_name', 'user_email'), ); $users = get_users($args); $formatted_users = array(); foreach ($users as $user) { $formatted_users[] = array( 'user_id' => $user->ID, 'user_name' => $user->display_name, 'user_avatar' => get_avatar_url($user->ID), ); } return rest_ensure_response($formatted_users); } public function create_comment($request) { $comment = HelperFunctions::sanitize_text(isset($request['comment']) ? $request['comment'] : '[]'); $post_id = HelperFunctions::sanitize_text(isset($request['post_id']) ? $request['post_id'] : ''); $parent_id = HelperFunctions::sanitize_text(isset($request['parent_id']) ? $request['parent_id'] : 0); $status = HelperFunctions::sanitize_text(isset($request['status']) ? $request['status'] : 1); $meta_data = HelperFunctions::sanitize_text(isset($request['meta_data']) ? $request['meta_data'] : '[]'); $session_id = HelperFunctions::sanitize_text(isset($request['session_id']) ? $request['session_id'] : ''); $user_id = get_current_user_id(); global $wpdb; $table_name = $wpdb->prefix . KIRKI_COMMENTS_TABLE; $wpdb->query( $wpdb->prepare( "INSERT INTO $table_name (user_id, post_id, parent_id, comment, meta_data, status ) VALUES ( %d, %d, %d, %s, %s, %d )", $user_id, $post_id, $parent_id, $comment, $meta_data, $status ) ); $comment_id = $wpdb->insert_id; if ($parent_id === '0') { $seen_table_name = $wpdb->prefix . KIRKI_COMMENTS_TABLE . '_seen'; $wpdb->query( $wpdb->prepare( "INSERT INTO $seen_table_name (user_id, comment_id) VALUES ( %d, %d )", $user_id, $comment_id ) ); } else { $seen_table_name = $wpdb->prefix . KIRKI_COMMENTS_TABLE . '_seen'; $wpdb->query( $wpdb->prepare( "DELETE FROM $seen_table_name WHERE comment_id = %d AND user_id != %d", $parent_id, $user_id ) ); } $comment = $this->get_single_comment($comment_id); $data = array( 'type' => 'COLLABORATION_ADD_KIRKI_COMMENT', 'payload' => array('comment' => array_merge($comment, array('read' => '0'))), ); Collaboration::save_action_to_db('post', $post_id, $data, 1, $session_id); return rest_ensure_response($comment); } /** * get_all_comments * * @param \WP_REST_Request $request all user request parameter. * * @return \WP_Error|WP_REST_Response */ public function get_all_comments($request) { global $wpdb; $post_id = HelperFunctions::sanitize_text(isset($request['post_id']) ? $request['post_id'] : null); $current_page = HelperFunctions::sanitize_text(isset($request['page']) ? $request['page'] : 1); $per_page = HelperFunctions::sanitize_text(isset($request['per_page']) ? $request['per_page'] : 20); $user_id = get_current_user_id(); $table_name = $wpdb->prefix . KIRKI_COMMENTS_TABLE; $seen_table_name = $wpdb->prefix . KIRKI_COMMENTS_TABLE . '_seen'; $offset = ($current_page - 1) * $per_page; $params = array(); // Escape table names for security $table_name_esc = esc_sql($table_name); $seen_table_name_esc = esc_sql($seen_table_name); $read_data = "CASE WHEN $seen_table_name_esc.comment_id IS NOT NULL THEN 1 ELSE 0 END AS `read`"; $read_join = "LEFT JOIN $seen_table_name_esc ON $table_name_esc.id = $seen_table_name_esc.comment_id AND $seen_table_name_esc.user_id = %d"; $params[] = $user_id; $where = "WHERE $table_name_esc.parent_id = %d"; $params[] = 0; if ($post_id !== null) { $where .= " AND $table_name_esc.post_id = %d"; $params[] = $post_id; } $sql = " SELECT $table_name_esc.*, $read_data FROM $table_name_esc $read_join $where ORDER BY $table_name_esc.created_at DESC LIMIT %d, %d "; $params[] = $offset; $params[] = $per_page; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Table names are escaped with esc_sql() above $all_comments = $wpdb->get_results($wpdb->prepare($sql, $params), ARRAY_A); foreach ($all_comments as $key => $comment) { $all_comments[$key] = $this->format_single_comment($comment); } // Count query (also conditionally add post_id) $count_where = 'WHERE parent_id = 0'; $count_args = array(); if ($post_id !== null) { $count_where .= ' AND post_id = %d'; $count_args[] = $post_id; } $count_sql = "SELECT COUNT(*) FROM $table_name $count_where"; if (!empty($count_args)) { $count = $wpdb->get_var($wpdb->prepare($count_sql, $count_args)); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared } else { $count = $wpdb->get_var($count_sql); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared } $res = array( 'total' => $count, 'per_page' => $per_page, 'current_page' => $current_page, 'data' => $all_comments, ); return rest_ensure_response($res); } private function get_single_comment($comment_id) { global $wpdb; $user_id = get_current_user_id(); $table_name = $wpdb->prefix . KIRKI_COMMENTS_TABLE; $seen_table_name = $wpdb->prefix . KIRKI_COMMENTS_TABLE . '_seen'; $read_data = "CASE WHEN $seen_table_name.comment_id IS NOT NULL THEN 1 ELSE 0 END AS `read`"; $read_join = $wpdb->prepare("LEFT JOIN $seen_table_name ON $table_name.id = $seen_table_name.comment_id AND $seen_table_name.user_id = %d", $user_id); $sql = $wpdb->prepare("SELECT $table_name.*, $read_data FROM $table_name $read_join WHERE $table_name.id = %d", $comment_id); $comment = $wpdb->get_row($sql, ARRAY_A); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared return $this->format_single_comment($comment); } private function format_single_comment($comment) { $comment['replies'] = $this->get_all_replies($comment['id']); $comment['meta_data'] = json_decode($comment['meta_data'], true); $comment['comment'] = json_decode($comment['comment'], true); $comment['user_avatar'] = get_avatar_url($comment['user_id']); $comment['user_name'] = get_the_author_meta('display_name', $comment['user_id']); return $comment; } private function get_all_replies($comment_id) { global $wpdb; $table_name = $wpdb->prefix . KIRKI_COMMENTS_TABLE; $sql = $wpdb->prepare("SELECT * FROM $table_name WHERE parent_id = %d ORDER BY created_at ASC", $comment_id); $all_replies = $wpdb->get_results($sql, ARRAY_A); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared foreach ($all_replies as $key => $reply) { $all_replies[$key] = $this->format_single_comment($reply); } return $all_replies; } public function get_item_permissions_check($request) { if (HelperFunctions::is_api_call_from_editor_preview() && HelperFunctions::is_api_header_post_editor_preview_token_valid()) { return true; } return HelperFunctions::has_access( array( KIRKI_ACCESS_LEVELS['FULL_ACCESS'], KIRKI_ACCESS_LEVELS['CONTENT_ACCESS'], KIRKI_ACCESS_LEVELS['VIEW_ACCESS'], ) ); } public function create_item_permissions_check($request) { return HelperFunctions::has_access( array( KIRKI_ACCESS_LEVELS['FULL_ACCESS'], KIRKI_ACCESS_LEVELS['CONTENT_ACCESS'], ) ); } }