HEX
Server: LiteSpeed
System: Linux server315.web-hosting.com 4.18.0-553.54.1.lve.el8.x86_64 #1 SMP Wed Jun 4 13:01:13 UTC 2025 x86_64
User: globfdxw (6114)
PHP: 8.1.34
Disabled: NONE
Upload Files
File: //home/globfdxw/www/wp-content/plugins/kirki/includes/API/KirkiComments/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
 */
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'],
			)
		);
	}
}