OwlCyberSecurity - MANAGER
Edit File: class-dco-ca-admin.php
<?php /** * Admin functions: DCO_CA_Admin class * * @package DCO_Comment_Attachment * @author Denis Yanchevskiy * @copyright 2019 * @license GPLv2+ * * @since 1.0.0 */ defined( 'ABSPATH' ) || die; /** * Class with admin functions. * * @since 1.0.0 * * @see DCO_CA_Base */ class DCO_CA_Admin extends DCO_CA_Base { /** * Constructor * * @since 1.0.0 */ public function __construct() { add_action( 'init', array( $this, 'init_hooks' ) ); } /** * Initializes hooks. * * @since 1.0.0 */ public function init_hooks() { parent::init_hooks(); add_filter( 'comment_row_actions', array( $this, 'add_comment_action_links' ), 10, 2 ); add_action( 'admin_action_deletecommentattachment', array( $this, 'delete_attachment_action' ) ); add_filter( 'bulk_actions-edit-comments', array( $this, 'add_comments_bulk_actions' ) ); add_action( 'admin_action_deleteattachment', array( $this, 'delete_attachment_bulk_action' ) ); add_filter( 'ngettext', array( $this, 'show_bulk_action_message' ), 10, 5 ); add_filter( 'removable_query_args', array( $this, 'add_removable_query_args' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); add_action( 'wp_ajax_delete_attachment', array( $this, 'delete_attachment_ajax' ) ); add_action( 'add_meta_boxes_comment', array( $this, 'add_attachment_metabox' ) ); add_action( 'edit_comment', array( $this, 'update_attachment' ) ); add_action( 'rest_insert_comment', array( $this, 'update_rest_api_attachment' ), 10, 3 ); add_filter( 'plugin_action_links_' . DCO_CA_BASENAME, array( $this, 'add_plugin_links' ) ); add_filter( 'comment_notification_text', array( $this, 'add_attachments_to_new_comment_email' ), 10, 2 ); add_filter( 'comment_moderation_text', array( $this, 'add_attachments_to_new_comment_email' ), 10, 2 ); if ( $this->get_option( 'delete_with_comment' ) ) { add_action( 'delete_comment', array( $this, 'delete_attachment' ) ); } } /** * Adds additional comment action links. * * @since 1.0.0 * * @param array $actions An array of comment actions. * @param WP_Comment $comment The comment object. * @return array An array with standard comment actions * and attachment actions if attachment exists. */ public function add_comment_action_links( $actions, $comment ) { if ( $this->has_attachment() ) { $comment_id = (int) $comment->comment_ID; $nonce = wp_create_nonce( "delete-comment-attachment_$comment_id" ); $del_attach_nonce = esc_html( '_wpnonce=' . $nonce ); $url = esc_url( "comment.php?c=$comment_id&action=deletecommentattachment&$del_attach_nonce" ); $title = esc_html__( 'Delete Attachment', 'dco-comment-attachment' ); $actions['deletecommentattachment'] = "<a href='$url' class='dco-del-attachment' data-id='$comment_id' data-nonce='$nonce'>$title</a>"; } return $actions; } /** * Handles a request to delete an attachment on the comments page. * * @since 1.0.0 */ public function delete_attachment_action() { $comment_id = isset( $_GET['c'] ) ? (int) $_GET['c'] : 0; check_admin_referer( 'delete-comment-attachment_' . $comment_id ); if ( ! function_exists( 'comment_footer_die' ) ) { require_once ABSPATH . 'wp-admin/includes/comment.php'; } $comment = get_comment( $comment_id ); // Check the comment exists. if ( ! $comment ) { comment_footer_die( esc_html__( 'Invalid comment ID.', 'dco-comment-attachment' ) . sprintf( ' <a href="%s">' . esc_html__( 'Go back', 'dco-comment-attachment' ) . '</a>.', 'edit-comments.php' ) ); } if ( ! current_user_can( 'edit_comment', $comment_id ) ) { comment_footer_die( esc_html__( 'Sorry, you are not allowed to edit comments on this post.', 'dco-comment-attachment' ) ); } if ( ! $this->has_attachment( $comment_id ) ) { comment_footer_die( esc_html__( 'The comment has no attachment.', 'dco-comment-attachment' ) . sprintf( ' <a href="%s">' . esc_html__( 'Go back', 'dco-comment-attachment' ) . '</a>.', 'edit-comments.php' ) ); } $delete = $this->get_option( 'delete_attachment_action' ); if ( ! $this->delete_attachment( $comment_id, $delete ) ) { comment_footer_die( esc_html__( 'An error occurred while deleting the attachment.', 'dco-comment-attachment' ) ); } $redir = admin_url( 'edit-comments.php?p=' . (int) $comment->comment_post_ID ); $redir = add_query_arg( array( 'attachmentdeleted' => 1 ), $redir ); wp_safe_redirect( $redir ); exit(); } /** * Adds additional bulk actions. * * @since 2.4.0 * * @param array $actions An array of the available bulk actions. * @return array An array with standard bulk actions * and attachment bulk actions. */ public function add_comments_bulk_actions( $actions ) { $actions['deleteattachment'] = __( 'Delete Attachment', 'dco-comment-attachment' ); return $actions; } /** * Handles a bulk action to delete comment attachments on the comments page. * * @since 2.4.0 */ public function delete_attachment_bulk_action() { check_admin_referer( 'bulk-comments' ); if ( isset( $_REQUEST['delete_comments'] ) && is_array( $_REQUEST['delete_comments'] ) ) { $comment_ids = array_map( 'absint', $_REQUEST['delete_comments'] ); } else { return; } $redirect_to = remove_query_arg( array( 'trashed', 'untrashed', 'deleted', 'spammed', 'unspammed', 'approved', 'unapproved', 'ids', 'deletedattachment' ), wp_get_referer() ); wp_defer_comment_counting( true ); $count = 0; foreach ( $comment_ids as $comment_id ) { if ( ! current_user_can( 'edit_comment', $comment_id ) ) { continue; } $comment = get_comment( $comment_id ); if ( ! $comment ) { continue; } $delete = $this->get_option( 'delete_attachment_action' ); if ( $this->delete_attachment( $comment_id, $delete ) ) { $count ++; } } wp_defer_comment_counting( false ); $redirect_to = add_query_arg( 'deletedattachment', $count, $redirect_to ); // @see DCO_CA_Admin::show_bulk_action_message() for details. $redirect_to = add_query_arg( 'approved', $count, $redirect_to ); wp_safe_redirect( $redirect_to ); exit; } /** * Shows bulk action updated message. * * @since 2.4.0 * * @param string $translation Translated text. * @param string $single The text to be used if the number is singular. * @param string $plural The text to be used if the number is plural. * @param string $number The number to compare against to use either the singular or plural form. * @param string $domain Text domain. Unique identifier for retrieving translated strings. * * @return string Filtered translated text. */ public function show_bulk_action_message( $translation, $single, $plural, $number, $domain ) { /** * There is no hook in WordPress to add updated message for custom comments bulk action. * So we override the approval message if attachment deletion was triggered. */ // phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized if ( ! isset( $_REQUEST['deletedattachment'] ) || ! $_REQUEST['deletedattachment'] ) { return $translation; } // phpcs:enable if ( '%s comment approved.' === $single && '%s comments approved.' === $plural && 'default' === $domain ) { /* translators: %s: Number of comments. */ $translation = sprintf( _n( 'Attachments deleted from %s comment.', 'Attachments deleted from %s comments.', $number, 'dco-comment-attachment' ), $number ); } return $translation; } /** * Adds single-use URL parameters. * * @since 2.4.0 * * @param array $removable_query_args An array of query variable names to remove from the URL. * @return array An array of query variable names to remove from the URL. */ public function add_removable_query_args( $removable_query_args ) { $removable_query_args[] = 'deletedattachment'; return $removable_query_args; } /** * Enqueues scripts and styles. * * @since 1.0.0 * * @param string $hook_suffix The current admin page. */ public function enqueue_scripts( $hook_suffix ) { // Only on comment edit page. if ( 'comment.php' === $hook_suffix ) { wp_enqueue_media(); } // Only on comments page and comment edit page. if ( in_array( $hook_suffix, array( 'edit-comments.php', 'comment.php', 'settings_page_dco-comment-attachment' ), true ) ) { wp_enqueue_script( 'dco-comment-attachment-admin', DCO_CA_URL . 'assets/dco-comment-attachment-admin.js', array( 'jquery' ), DCO_CA_VERSION, true ); $strings = array( 'set_attachment_title' => esc_attr__( 'Set Comment Attachment', 'dco-comment-attachment' ), 'add_attachment_label' => esc_attr__( 'Add Attachment', 'dco-comment-attachment' ), 'replace_attachment_label' => esc_attr__( 'Replace Attachment', 'dco-comment-attachment' ), 'delete_attachment_action' => $this->get_option( 'delete_attachment_action' ), 'delete_attachment_confirm' => esc_attr__( 'This action will delete the attachment from the Media Library and cannot be undone. Continue?', 'dco-comment-attachment' ), 'show_all' => esc_attr__( 'Show all', 'dco-comment-attachment' ), 'show_less' => esc_attr__( 'Show less', 'dco-comment-attachment' ), ); wp_localize_script( 'dco-comment-attachment-admin', 'dcoCA', $strings ); wp_enqueue_style( 'dco-comment-attachment-admin', DCO_CA_URL . 'assets/dco-comment-attachment-admin.css', array(), DCO_CA_VERSION ); } } /** * Handles an ajax request to delete an attachment on the comments page. * * @since 1.0.0 */ public function delete_attachment_ajax() { $comment_id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0; check_ajax_referer( "delete-comment-attachment_$comment_id" ); $comment = get_comment( $comment_id ); // Check the comment exists. if ( ! $comment ) { /* translators: %d: The comment ID */ wp_send_json_error( new WP_Error( 'invalid_comment', sprintf( esc_html__( 'Comment %d does not exist', 'dco-comment-attachment' ), $comment_id ) ) ); } if ( ! current_user_can( 'edit_comment', $comment_id ) ) { wp_send_json_error( new WP_Error( 'invalid_capability', esc_html__( 'Sorry, you are not allowed to edit comments on this post.', 'dco-comment-attachment' ) ) ); } if ( ! $this->has_attachment( $comment_id ) ) { wp_send_json_error( new WP_Error( 'attachment_not_exists', esc_html__( 'The comment has no attachment.', 'dco-comment-attachment' ) ) ); } $delete = $this->get_option( 'delete_attachment_action' ); if ( ! $this->delete_attachment( $comment_id, $delete ) ) { wp_send_json_error( new WP_Error( 'deleting_error', esc_html__( 'An error occurred while deleting the attachment.', 'dco-comment-attachment' ) ) ); } wp_send_json_success(); } /** * Adds the attachment metabox for the comment editing page. * * @since 1.0.0 */ public function add_attachment_metabox() { add_meta_box( 'dco-comment-attachment', esc_html__( 'Attachments', 'dco-comment-attachment' ), array( $this, 'render_attachment_metabox' ), 'comment', 'normal' ); } /** * Renders the attachment metabox on the comment editing page. * * @since 1.0.0 */ public function render_attachment_metabox() { if ( $this->has_attachment() ) : $attachment_id = $this->get_attachment_id(); foreach ( (array) $attachment_id as $attach_id ) : ?> <div class="dco-attachment-wrap"> <?php echo $this->get_attachment_preview( $attach_id ); // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped ?> <div class="dco-attachment-notice dco-hidden"><?php echo wp_kses_data( __( 'Update the comment to see a preview of <a href="#" target="_blank">the selected attachment</a>.', 'dco-comment-attachment' ) ); ?></div> <div class="dco-attachment-actions"> <a href="#" class="button dco-set-attachment"><?php esc_html_e( 'Replace Attachment', 'dco-comment-attachment' ); ?></a> <a href="#" class="dco-remove-attachment"><?php esc_html_e( 'Remove Attachment', 'dco-comment-attachment' ); ?></a> </div> <input type="hidden" name="dco_attachment_id[]" class="dco-attachment-id" value="<?php echo (int) $attach_id; ?>"> </div> <?php endforeach; endif; ?> <div class="dco-attachment-wrap"> <div class="dco-attachment-notice dco-hidden"><?php echo wp_kses_data( __( 'Update the comment to see a preview of <a href="#" target="_blank">the selected attachment</a>.', 'dco-comment-attachment' ) ); ?></div> <div class="dco-attachment-actions"> <a href="#" class="button dco-set-attachment"><?php echo esc_html_e( 'Add Attachment', 'dco-comment-attachment' ); ?></a> <a href="#" class="dco-remove-attachment dco-hidden"><?php esc_html_e( 'Remove Attachment', 'dco-comment-attachment' ); ?></a> </div> <input type="hidden" name="dco_attachment_id[]" class="dco-attachment-id" value=""> </div> <?php } /** * Adds additional actions for the plugin on the plugins page in the admin panel. * * @since 1.0.0 * * @param array $actions An array of plugin action links. * @return array An array of plugin action links with additional plugin actions. */ public function add_plugin_links( $actions ) { array_unshift( $actions, sprintf( '<a href="%1$s">%2$s</a>', admin_url( 'options-general.php?page=dco-comment-attachment' ), esc_html__( 'Settings', 'dco-comment-attachment' ) ) ); return $actions; } /** * Updates the attachment after editing the comment. * * @since 1.0.0 * * @param int $comment_id The comment ID. */ public function update_attachment( $comment_id ) { if ( ! function_exists( 'get_current_screen' ) ) { return false; } if ( 'comment' !== get_current_screen()->id ) { return false; } check_admin_referer( 'update-comment_' . $comment_id ); $attachment_id = isset( $_POST['dco_attachment_id'] ) ? array_map( 'intval', $_POST['dco_attachment_id'] ) : array(); // We need to delete the last empty element, because it's used // as a placeholder in the attachments edit form. // @see DCO_CA_Admin::render_attachment_metabox. array_pop( $attachment_id ); if ( $attachment_id ) { $this->assign_attachment( $comment_id, $attachment_id ); } else { $this->unassign_attachment( $comment_id ); } } /** * Updates attachments after comment is updated via REST API. * * @since 2.3.0 * * @param WP_Comment $comment Inserted or updated comment object. * @param WP_REST_Request $request Request object. * @param bool $creating True when creating a comment, false when updating. */ public function update_rest_api_attachment( $comment, $request, $creating ) { if ( $creating ) { return; } $attachment_id = isset( $request['dco_attachment_id'] ) ? array_map( 'intval', (array) $request['dco_attachment_id'] ) : array(); if ( $attachment_id ) { $this->assign_attachment( $comment->comment_ID, $attachment_id ); } else { $this->unassign_attachment( $comment->comment_ID ); } } /** * Deletes an assigned attachment. * * @since 1.0.0 * * @param int $comment_id The comment ID. * @param bool $delete True to unassign and remove an attachment, * false to unassign an attachment only. * @return bool True on success, false on failure. */ public function delete_attachment( $comment_id, $delete = true ) { if ( ! $this->has_attachment( $comment_id ) ) { return false; } $attachment_id = $this->get_attachment_id( $comment_id ); if ( $delete ) { $result = true; foreach ( (array) $attachment_id as $attach_id ) { if ( ! wp_delete_attachment( $attach_id ) ) { $result = false; } } return $result; } if ( ! $this->unassign_attachment( $comment_id ) ) { return false; } return true; } /** * Unassigns an attachment for the comment. * * @since 1.0.0 * * @param int $comment_id The comment ID. * @return int|bool Meta ID on success, false on failure. */ public function unassign_attachment( $comment_id ) { $meta_key = $this->get_attachment_meta_key(); return delete_comment_meta( $comment_id, $meta_key ); } /** * Adds links to attached attachments to the new comment notification email. * * @since 2.1.0 * * @param string $notify_message The comment notification email text. * @param int $comment_id Comment ID. * @return string The comment notification email text with links to attached attachments. */ public function add_attachments_to_new_comment_email( $notify_message, $comment_id ) { $attachment_id = $this->get_attachment_id( $comment_id ); if ( ! $attachment_id ) { return $notify_message; } $attachments_list = "\r\n" . __( 'Attached attachments:', 'dco-comment-attachment' ); foreach ( (array) $attachment_id as $attach_id ) { $attachments_list .= "\r\n- " . wp_get_attachment_url( $attach_id ); } return $notify_message . $attachments_list; } }