* @license GPL-3.0+
*
* @link https://anspress.io
*
* @copyright 2014 Rahul Aryan
* @package AnsPress/theme
*/
/**
* Comments class
*/
class AnsPress_Comment_Hooks {
/**
* Comment data.
*
* @param integer $post_id Post ID.
* @param boolean $editing Editing mode.
* @return array
*/
public static function comments_data( $post_id, $editing = false ) {
$user_id = get_current_user_id();
$args = array(
'post_id' => $post_id,
'order' => 'ASC',
'status' => 'approve',
);
// Always include current user comments.
if ( ! empty( $user_id ) && $user_id > 0 ) {
$args['include_unapproved'] = [ $user_id ];
}
if ( ap_user_can_approve_comment( ) ) {
$args['status'] = 'all';
}
$comments = get_comments( $args );
$comments_arr = array();
foreach ( (array) $comments as $c ) {
$comments_arr[] = ap_comment_ajax_data( $c );
}
if ( ! empty( $comments_arr ) ) {
return $comments_arr;
}
return [];
}
/**
* Ajax callback for loading comments.
*
* @since 2.0.1
* @since 3.0.0 Moved from AnsPress_Ajax class.
*/
public static function load_comments() {
$post_id = ap_sanitize_unslash( 'post_id', 'r' );
if ( ! check_ajax_referer( 'comment_form_nonce', '__nonce', false ) ) {
ap_ajax_json( array(
'success' => false,
'snackbar' => [ 'message' => __( 'Unable to load comments', 'anspress-question-answer' ) ],
));
}
$result = array(
'success' => true,
'action' => 'load_comment_form',
'comments' => SELF::comments_data( $post_id ),
);
ap_ajax_json( $result );
}
/**
* Process new comment submission.
*
* @since 3.0.0
*/
public static function new_comment() {
$post_id = (int) ap_sanitize_unslash( 'post_id', 'r' );
$content = ap_sanitize_unslash( 'content', 'r' );
if ( ! is_user_logged_in() || ! ap_verify_nonce( 'new-comment' ) || ! ap_user_can_comment( $post_id ) ) {
ap_ajax_json( array(
'success' => false,
'snackbar' => [ 'message' => __( 'Unable to post comment', 'anspress-question-answer' ) ],
) );
}
// Check if comment content is not empty.
if ( empty( $content ) ) {
ap_ajax_json( array(
'success' => false,
'snackbar' => [ 'message' => __( 'Sorry, you cannot post a blank comment', 'anspress-question-answer' ) ],
) );
}
$_post = ap_get_post( $post_id );
$type = 'question' === $_post->post_type ? __( 'question', 'anspress-question-answer' ) : __( 'answer', 'anspress-question-answer' );
// Check if not restricted post type.
if ( in_array( $_post->post_status, [ 'draft', 'pending', 'trash' ], true ) ) {
ap_ajax_json( array(
'success' => false,
'snackbar' => [ 'message' => sprintf( __( 'Commenting is not allowed on draft, pending or deleted %s', 'anspress-question-answer' ), $type ) ],
) );
}
// Get current user object.
$user = wp_get_current_user();
if ( ! $user->exists() ) {
ap_ajax_json( array(
'success' => false,
'snackbar' => [ 'message' => __( 'Sorry, you cannot post a comment', 'anspress-question-answer' ) ],
) );
}
$commentdata = array(
'comment_post_ID' => $_post->ID,
'comment_author' => wp_slash( $user->display_name ),
'comment_author_email' => wp_slash( $user->user_email ),
'comment_author_url' => wp_slash( $user->user_url ),
'comment_content' => trim( $content ),
'comment_type' => 'anspress',
'comment_parent' => 0,
'user_id' => $user->ID,
);
/**
* Filter comment content before inserting to DB.
*
* @param bool $apply_filter Apply this filter.
* @param string $content Un-filtered comment content.
*/
$commentdata = apply_filters( 'ap_pre_insert_comment', $commentdata );
// Insert new comment and get the comment ID.
$comment_id = wp_new_comment( $commentdata, true );
if ( ! is_wp_error( $comment_id ) && false !== $comment_id ) {
$c = get_comment( $comment_id );
do_action( 'ap_after_new_comment', $c );
$count = get_comment_count( $c->comment_post_ID );
$result = array(
'success' => true,
'comment' => ap_comment_ajax_data( $c ),
'action' => 'new-comment',
'commentsCount' => [ 'text' => sprintf( _n( '%d Comment', '%d Comments', $count['all'], 'anspress-question-answer' ), $count['all'] ), 'number' => $count['all'], 'unapproved' => $count['awaiting_moderation'] ],
'snackbar' => [ 'message' => __( 'Comment successfully posted', 'anspress-question-answer' ) ],
);
ap_ajax_json( $result );
}
// Lastly output error message.
ap_ajax_json( array(
'success' => false,
'snackbar' => [ 'message' => $comment_id->get_error_message() ],
) );
}
/**
* Updates comment.
*
* @since 3.0.0
*/
public static function edit_comment() {
$comment_id = ap_sanitize_unslash( 'comment_ID', 'r' );
$content = ap_sanitize_unslash( 'content', 'r' );
if ( ! is_user_logged_in() || ! ap_verify_nonce( 'edit-comment-' . $comment_id ) || ! ap_user_can_edit_comment( $comment_id ) ) {
ap_ajax_json( array(
'success' => false,
'snackbar' => [ 'message' => __( 'Sorry, you cannot edit this comment', 'anspress-question-answer' ) ],
) );
}
$comment = get_comment( $comment_id );
// Check if content is changed.
if ( $content === $comment->comment_content || empty( $content ) ) {
ap_ajax_json( [
'success' => false,
'snackbar' => [ 'message' => __( 'No change detected, edit comment and then try', 'anspress-question-answer' ) ],
] );
}
$updated = wp_update_comment( array(
'comment_ID' => $comment_id,
'comment_content' => $content,
) );
if ( $updated ) {
$c = get_comment( $comment_id );
$count = get_comment_count( $c->comment_post_ID );
$result = array(
'success' => true,
'comment' => ap_comment_ajax_data( $c ),
'action' => 'edit-comment',
'commentsCount' => [ 'text' => sprintf( _n( '%d Comment', '%d Comments', $count['all'], 'anspress-question-answer' ), $count['all'] ), 'number' => $count['all'], 'unapproved' => $count['awaiting_moderation'] ],
'snackbar' => [ 'message' => __( 'Comment updated successfully', 'anspress-question-answer' ) ],
);
ap_ajax_json( $result );
}
ap_ajax_json( array(
'success' => false,
'snackbar' => [ 'message' => __( 'Unable to update comment', 'anspress-question-answer' ) ],
) );
}
/**
* Ajax action for deleting comment.
*
* @since 2.0.0
* @since 3.0.0 Moved from ajax.php to here.
*/
public static function delete_comment() {
$comment_id = (int) ap_sanitize_unslash( 'comment_ID', 'r' );
if ( ! $comment_id || ! ap_user_can_delete_comment( $comment_id ) || ! ap_verify_nonce( 'delete_comment' ) ) {
ap_ajax_json( array(
'success' => false,
'snackbar' => [ 'message' => __( 'Failed to delete comment', 'anspress-question-answer' ) ],
) );
}
$_comment = get_comment( $comment_id );
// Check if deleting comment is locked.
if ( ap_comment_delete_locked( $_comment->comment_ID ) && ! is_super_admin() ) {
ap_ajax_json( array(
'success' => false,
'snackbar' => [ 'message' => sprintf( __( 'This comment was created %s. Its locked hence you cannot delete it.', 'anspress-question-answer' ), ap_human_time( $_comment->comment_date_gmt, false ) ) ],
) );
}
$delete = wp_delete_comment( (integer) $_comment->comment_ID, true );
if ( $delete ) {
do_action( 'ap_unpublish_comment', $_comment );
do_action( 'ap_after_deleting_comment', $_comment );
$count = get_comment_count( $_comment->comment_post_ID );
ap_ajax_json( array(
'success' => true,
'snackbar' => [ 'message' => __( 'Comment successfully deleted', 'anspress-question-answer' ) ],
'action' => 'delete_comment',
'commentsCount' => [ 'text' => sprintf( _n( '%d Comment', '%d Comments', $count['all'], 'anspress-question-answer' ), $count['all'] ), 'number' => $count['all'], 'unapproved' => $count['awaiting_moderation'] ],
) );
}
}
/**
* Modify comment query args for showing pending comments to moderator.
*
* @param array $args Comment args.
* @return array
* @since 3.0.0
*/
public static function comments_template_query_args( $args ) {
if ( ap_user_can_approve_comment() ) {
$args['status'] = 'all';
}
return $args;
}
/**
* Ajax callback to approve comment.
*/
public static function approve_comment() {
$comment_id = (int) ap_sanitize_unslash( 'comment_ID', 'r' );
if ( ! ap_verify_nonce( 'approve_comment_' . $comment_id ) || ! ap_user_can_approve_comment( ) ) {
ap_ajax_json( array(
'success' => false,
'snackbar' => [ 'message' => __( 'Sorry, unable to approve comment', 'anspress-question-answer' ) ],
) );
}
$success = wp_set_comment_status( $comment_id, 'approve' );
$_comment = get_comment( $comment_id );
$count = get_comment_count( $_comment->comment_post_ID );
if ( $success ) {
$_comment = get_comment( $comment_id );
ap_ajax_json( array(
'success' => true,
'action' => 'comment_approved',
'model' => [ 'approved' => '1', 'actions' => ap_comment_actions( $_comment ) ],
'comment_ID' => $comment_id,
'commentsCount' => [ 'text' => sprintf( _n( '%d Comment', '%d Comments', $count['all'], 'anspress-question-answer' ), $count['all'] ), 'number' => $count['all'], 'unapproved' => $count['awaiting_moderation'] ],
'snackbar' => [ 'message' => __( 'Comment approved successfully.', 'anspress-question-answer' ) ],
) );
}
}
/**
* Manipulate question and answer comments link.
*
* @param string $link The comment permalink with '#comment-$id' appended.
* @param WP_Comment $comment The current comment object.
* @param array $args An array of arguments to override the defaults.
*/
public static function comment_link( $link, $comment, $args ) {
$_post = ap_get_post( $comment->comment_post_ID );
if ( ! in_array( $_post->post_type, [ 'question', 'answer' ], true ) ) {
return $link;
}
$permalink = get_permalink( $_post );
return $permalink . '#/comment/' . $comment->comment_ID;
}
/**
* Ajax callback to get a single comment.
*/
public static function get_comment() {
$comment_id = ap_sanitize_unslash( 'comment_id', 'r' );
$c = get_comment( $comment_id );
// Check if user can read post.
if ( ! ap_user_can_read_post( $c->comment_post_ID ) ) {
wp_die();
}
if ( '1' !== $c->comment_approved && ! ( ap_user_can_delete_comment( $c->comment_ID ) || ap_user_can_approve_comment( $c->comment_ID ) ) ) {
wp_die();
}
ap_ajax_json( array(
'success' => true,
'comment' => ap_comment_ajax_data( $c, false ),
) );
}
}
/**
* Load comment form button.
*
* @param mixed $_post Echo html.
* @return string
* @since 0.1
*/
function ap_comment_btn_html( $_post = null ) {
$_post = ap_get_post( $_post );
if ( 'question' === $_post->post_type && ap_opt( 'disable_comments_on_question' ) ) {
return;
}
if ( 'answer' === $_post->post_type && ap_opt( 'disable_comments_on_answer' ) ) {
return;
}
$comment_count = get_comments_number( $_post->ID );
$args = wp_json_encode( [ 'post_id' => $_post->ID, '__nonce' => wp_create_nonce( 'comment_form_nonce' ) ] );
$q = wp_json_encode( array(
'post_id' => get_the_ID(),
'__nonce' => wp_create_nonce( 'new-comment' ),
'ap_ajax_action' => 'new_comment',
) );
$unapproved = '';
if ( ap_user_can_approve_comment() ) {
$unapproved_count = ! empty( $_post->fields['unapproved_comments'] ) ? (int) $_post->fields['unapproved_comments'] : 0;
$unapproved = '' . $unapproved_count . '';
}
$output = '';
return $output;
}
/**
* Comment actions args.
*
* @param object|integer $comment Comment object.
* @return array
* @since 4.0.0
*/
function ap_comment_actions( $comment ) {
$comment = get_comment( $comment );
$actions = [];
if ( ap_user_can_edit_comment( $comment->comment_ID ) ) {
$actions[] = [ 'label' => __( 'Edit', 'anspress-question-answer' ), 'cb' => 'edit_comment', 'query' => [ '__nonce' => wp_create_nonce( 'edit-comment-' . $comment->comment_ID ), 'comment_ID' => $comment->comment_ID, 'post_id' => $comment->comment_post_ID, 'ap_ajax_action' => 'edit_comment' ] ];
}
if ( ap_user_can_delete_comment( $comment->comment_ID ) ) {
$actions[] = [ 'label' => __( 'Delete', 'anspress-question-answer' ), 'query' => [ '__nonce' => wp_create_nonce( 'delete_comment' ), 'comment_ID' => $comment->comment_ID, 'ap_ajax_action' => 'delete_comment' ] ];
}
if ( '0' === $comment->comment_approved && ap_user_can_approve_comment( ) ) {
$actions[] = [ 'label' => __( 'Approve', 'anspress-question-answer' ), 'query' => [ '__nonce' => wp_create_nonce( 'approve_comment_' . $comment->comment_ID ), 'comment_ID' => $comment->comment_ID, 'ap_ajax_action' => 'approve_comment' ] ];
}
/**
* For filtering comment action buttons.
*
* @param array $actions Comment actions.
* @since 2.0.0
*/
return apply_filters( 'ap_comment_actions', $actions );
}
/**
* Check if comment delete is locked.
* @param integer $comment_ID Comment ID.
* @return bool
* @since 3.0.0
*/
function ap_comment_delete_locked( $comment_ID ) {
$comment = get_comment( $comment_ID );
$commment_time = mysql2date( 'U', $comment->comment_date_gmt ) + (int) ap_opt( 'disable_delete_after' );
return current_time( 'timestamp', true ) > $commment_time;
}
/**
* Output comment wrapper.
*
* @return void
* @since 2.1
*/
function ap_the_comments() {
global $post;
if ( ( 'answer' === $post->post_type && ! ap_opt( 'disable_comments_on_answer' ) ) || 'question' === $post->post_type ) {
echo '';
}
}
/**
* Return ajax comment data.
*
* @param object $c Comment object.
* @return array
* @since 4.0.0
*/
function ap_comment_ajax_data( $c, $actions = true ) {
return array(
'ID' => $c->comment_ID,
'link' => get_comment_link( $c ),
'avatar' => get_avatar( $c->user_id, 30 ),
'user_link' => ap_user_link( $c->user_id ),
'user_name' => ap_user_display_name( $c->user_id ),
'iso_date' => date( 'c', strtotime( $c->comment_date ) ),
'time' => ap_human_time( $c->comment_date_gmt, false ),
'content' => $c->comment_content,
'approved' => $c->comment_approved,
'class' => implode( ' ', get_comment_class( 'ap-comment', $c->comment_ID, null, false ) ),
'actions' => $actions ? ap_comment_actions( $c ) : [],
);
}