'adminkeep_include_approved', 'label' => __( 'Also delete approved and pending comments', 'adminkeep' ), ), ); if ( $counts['wooActive'] ) { $toggles[] = array( 'name' => 'adminkeep_include_woo', 'label' => __( 'Also delete WooCommerce order notes, webhook logs and product reviews', 'adminkeep' ), ); } return array( array( 'id' => self::PURGE_ARG, 'label' => __( 'Delete spam and trashed comments', 'adminkeep' ), 'description' => $this->purge_description( $counts ), 'destructive' => true, 'disabled' => 0 === $counts['allWoo'], 'counts' => $counts, 'toggles' => $toggles, ), ); } /** * Explain the scope in the numbers that apply to this site. * * @param array $counts Counts from CommentPurger. * @return string */ private function purge_description( array $counts ) { $base = sprintf( /* translators: 1: spam/trash count, 2: count including approved. */ __( 'Permanently removes the %1$s comments already marked spam or already in the trash. Approved and pending comments are left alone unless you tick the box — that would be %2$s in total.', 'adminkeep' ), number_format_i18n( $counts['spamTrash'] ), number_format_i18n( $counts['all'] ) ); if ( $counts['wooActive'] ) { $base .= ' ' . sprintf( /* translators: %s: number of WooCommerce entries. */ __( 'WooCommerce keeps order notes in the comments table — %s entries here — and those are excluded unless you tick the WooCommerce box.', 'adminkeep' ), number_format_i18n( $counts['allWoo'] - $counts['all'] ) ); } return $base . ' ' . __( 'Nothing here can be undone, so you will be asked to confirm.', 'adminkeep' ); } /** * What switching this on actually does. Shown on the settings screen. * * @return string[] */ public function how_it_works() { return array( __( 'Removes comment and trackback support from every post type, in the editor and on the front end.', 'adminkeep' ), __( 'Rejects direct POSTs to wp-comments-post.php with a 403 — the route spam bots actually use, since they never load your page.', 'adminkeep' ), __( 'Rejects comment creation through the REST API.', 'adminkeep' ), __( 'Hides existing comments instead of deleting them. No comment_status column is written, so switching this off restores everything with nothing to repair.', 'adminkeep' ), __( 'Clears the Comments menu, the admin-bar bubble and the dashboard widget.', 'adminkeep' ), ); } /** * Register hooks. * * @param array $settings Resolved settings. Unused — this feature has none. * @return void */ public function boot( array $settings ) { // Drop editor and theme support for comments everywhere. add_action( 'init', array( $this, 'remove_post_type_support' ), 100 ); // Closed, for every consumer that asks the right question. add_filter( 'comments_open', '__return_false', 100 ); add_filter( 'pings_open', '__return_false', 100 ); // Hide what already exists, without deleting it. add_filter( 'comments_array', '__return_empty_array', 100 ); add_filter( 'get_comments_number', '__return_zero', 100 ); // Feeds. add_filter( 'feed_links_show_comments_feed', '__return_false', 100 ); // The part most implementations skip: bots POST straight to wp-comments-post.php and // never need the form to have been rendered. add_action( 'pre_comment_on_post', array( $this, 'block_direct_post' ), 0 ); // Same door, REST edition. add_filter( 'rest_pre_insert_comment', array( $this, 'block_rest_insert' ), 100 ); if ( is_admin() ) { add_action( 'admin_menu', array( $this, 'remove_admin_menu' ), 100 ); add_action( 'wp_dashboard_setup', array( $this, 'remove_dashboard_widget' ), 100 ); } add_action( 'wp_before_admin_bar_render', array( $this, 'remove_admin_bar_node' ), 100 ); } /** * Remove comment and trackback support from every post type. * * @return void */ public function remove_post_type_support() { foreach ( get_post_types( array(), 'names' ) as $post_type ) { remove_post_type_support( $post_type, 'comments' ); remove_post_type_support( $post_type, 'trackbacks' ); } } /** * Reject a direct POST to wp-comments-post.php. * * Runs at priority 0 on pre_comment_on_post, before core does any processing, so no row is * ever created and no notification is ever sent. * * @return void */ public function block_direct_post() { wp_die( esc_html__( 'Comments are closed.', 'adminkeep' ), esc_html__( 'Comments are closed.', 'adminkeep' ), array( 'response' => 403 ) ); } /** * Reject comment creation over the REST API. * * @param array|\WP_Error $prepared Prepared comment data. * @return \WP_Error */ public function block_rest_insert( $prepared ) { if ( is_wp_error( $prepared ) ) { return $prepared; } return new \WP_Error( 'adminkeep_comments_closed', __( 'Comments are closed.', 'adminkeep' ), array( 'status' => 403 ) ); } /** * Remove the Comments admin menu. * * @return void */ public function remove_admin_menu() { remove_menu_page( 'edit-comments.php' ); } /** * Remove the Recent Comments dashboard widget. * * @return void */ public function remove_dashboard_widget() { remove_meta_box( 'dashboard_recent_comments', 'dashboard', 'normal' ); } /** * Remove the admin bar comments bubble. * * @return void */ public function remove_admin_bar_node() { global $wp_admin_bar; if ( is_object( $wp_admin_bar ) ) { $wp_admin_bar->remove_node( 'comments' ); } } }