diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2f0da8b..f307e08 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,6 @@
#### Version 1.0.0 - 2024/11/12
* initial release
+
+#### Version 1.1.0 - 2024/11/18
+* adding admin UI button for running bulk update
diff --git a/README.md b/README.md
index 7f0bb91..e00ddfc 100644
--- a/README.md
+++ b/README.md
@@ -10,10 +10,9 @@ Make sure no real IP addresses are stored in WP comments.
### Features
-* a CLI command to bulk convert existing comment IP addresses to the masked
+* a CLI command and admin UI to bulk convert existing comment IP addresses to the masked
* auto-filtering of new comments to use masked IP.
### To Do
-* add admin UI piece to bulk convert existing comments
* add whitelisting of IPs
diff --git a/includes/activate.php b/includes/activate.php
index d221e53..40bad63 100644
--- a/includes/activate.php
+++ b/includes/activate.php
@@ -23,8 +23,5 @@ function activate() {
// Include our action so that we may add to this later.
do_action( Core\HOOK_PREFIX . 'activate_process' );
-
- // And flush our rewrite rules.
- flush_rewrite_rules();
}
register_activation_hook( Core\FILE, __NAMESPACE__ . '\activate' );
diff --git a/includes/bulk-process.php b/includes/bulk-process.php
new file mode 100644
index 0000000..ee65184
--- /dev/null
+++ b/includes/bulk-process.php
@@ -0,0 +1,200 @@
+ true ] );
+ }
+
+ // Now get the IDs of the comments we have.
+ $fetch_comments = Database\get_ids_for_update();
+
+ // If none exist, say so.
+ if ( empty( $fetch_comments ) ) {
+
+ // Now set my redirect link.
+ $redirect_link = Helpers\fetch_settings_url( ['ip-scrub-bulk-error' => 'no-comments', 'ip-scrub-bulk-success' => 'no'] );
+
+ // Do the redirect.
+ wp_safe_redirect( $redirect_link );
+ exit;
+ }
+
+ // Handle the WP_Error return on it's own.
+ if ( is_wp_error( $fetch_comments ) ) {
+
+ // Now set my redirect link.
+ $redirect_link = Helpers\fetch_settings_url( ['ip-scrub-bulk-error' => 'query-error', 'ip-scrub-bulk-success' => 'no'] );
+
+ // Do the redirect.
+ wp_safe_redirect( $redirect_link );
+ exit;
+ }
+
+ // Attempt the update.
+ $attempt_update = Database\replace_batch_comment_ips( $fetch_comments );
+
+ // Bail if the update did.
+ if ( empty( $attempt_update ) || is_wp_error( $attempt_update ) ) {
+
+ // Now set my redirect link.
+ $redirect_link = Helpers\fetch_settings_url( ['ip-scrub-bulk-error' => 'update-error', 'ip-scrub-bulk-success' => 'no'] );
+
+ // Do the redirect.
+ wp_safe_redirect( $redirect_link );
+ exit;
+ }
+
+ // Now set my redirect link.
+ $redirect_link = Helpers\fetch_settings_url( ['ip-scrub-bulk-count' => count( $fetch_comments ), 'ip-scrub-bulk-success' => 'yes'] );
+
+ // Do the redirect.
+ wp_safe_redirect( $redirect_link );
+ exit;
+}
+
+/**
+ * Check for the result of bulk action.
+ *
+ * @return void
+ */
+function admin_bulk_action_notice() {
+
+ // Confirm we requested this action.
+ $confirm_result = filter_input( INPUT_GET, 'ip-scrub-bulk-success', FILTER_SANITIZE_SPECIAL_CHARS ); // phpcs:ignore -- no need for a nonce check.
+
+ // Make sure it is what we want.
+ if ( empty( $confirm_result ) ) {
+ return;
+ }
+
+ // Handle the success first.
+ if ( 'yes' === $confirm_result ) {
+
+ // Set the counts.
+ $set_counts = filter_input( INPUT_GET, 'ip-scrub-bulk-count', FILTER_SANITIZE_NUMBER_INT );
+
+ // Set our notice text.
+ $set_notice = sprintf( _n( 'Success! %d comment was updated.', 'Success! %d comments were updated.', absint( $set_counts ), 'scrub-comment-author-ip' ), absint( $set_counts ) );
+
+ // Set the wrapper around it.
+ echo '
';
+
+ // Display the actual message.
+ echo '
' . wp_kses_post( $set_notice ) . '
';
+
+ // Close the wrapper.
+ echo '
';
+
+ // And be done.
+ return;
+ }
+
+ // Handle the errors now.
+ $set_error = filter_input( INPUT_GET, 'ip-scrub-bulk-error', FILTER_SANITIZE_SPECIAL_CHARS );
+
+ // If we have no comments, show a warning.
+ if ( 'no-comments' === $set_error ) {
+
+ // Set the notice text.
+ $set_notice = __( 'There are no comments requiring update at this time.', 'scrub-comment-author-ip' );
+
+ // Set the wrapper around it.
+ echo '
';
+
+ // Display the actual message.
+ echo '
' . wp_kses_post( $set_notice ) . '
';
+
+ // Close the wrapper.
+ echo '
';
+
+ // And finish.
+ return;
+ }
+
+ // Handle the rest of the possible error messages.
+ switch ( $set_error ) {
+
+ case 'query-error' :
+ $set_notice = __( 'There was an error attempting to retrieve the comments. Please check your error logs.', 'scrub-comment-author-ip' );
+ break;
+
+ case 'update-error' :
+ $set_notice = __( 'There was an error attempting to update the comments. Please check your error logs.', 'scrub-comment-author-ip' );
+ break;
+
+ default :
+ $set_notice = __( 'There was an unknown error. Please check your error logs.', 'scrub-comment-author-ip' );
+ break;
+ }
+
+ // Set the wrapper around it.
+ echo '
';
+
+ // Display the actual message.
+ echo '
' . wp_kses_post( $set_notice ) . '
';
+
+ // Close the wrapper.
+ echo '
';
+
+ // Nothing left to display.
+}
+
+/**
+ * Add our custom strings to the vars.
+ *
+ * @param array $args The existing array of args.
+ *
+ * @return array $args The modified array of args.
+ */
+function admin_removable_args( $args ) {
+
+ // Set an array of the args we wanna exclude.
+ $remove = [
+ 'ip-scrub-bulk-error',
+ 'ip-scrub-bulk-count',
+ 'ip-scrub-bulk-success',
+ ];
+
+ // Include my new args and return.
+ return wp_parse_args( $remove, $args );
+}
diff --git a/includes/database.php b/includes/database.php
index cdcc515..bb5e210 100644
--- a/includes/database.php
+++ b/includes/database.php
@@ -15,6 +15,38 @@
// And pull in any other namespaces.
use WP_Error;
+/**
+ * Just get a simple count.
+ *
+ * @return array
+ */
+function get_count_for_update() {
+
+ // Fetch the masked IP.
+ $masked_ip = Helpers\fetch_masked_ip();
+
+ // Call the global class.
+ global $wpdb;
+
+ // Set up our query.
+ $query_args = $wpdb->prepare("
+ SELECT COUNT(*)
+ FROM $wpdb->comments
+ WHERE comment_author_IP NOT LIKE '%s'
+ ", esc_attr( $masked_ip ) );
+
+ // Process the query.
+ $query_run = $wpdb->get_var( $query_args ); // phpcs:ignore -- we are skipping the overhead of get_comments.
+
+ // Throw the error if we have one.
+ if ( is_wp_error( $query_run ) ) {
+ return new WP_Error( $query_run->get_error_code(), $query_run->get_error_message() );
+ }
+
+ // Return the count, whatever it may be.
+ return absint( $query_run );
+}
+
/**
* Get all my comment IDs.
*
@@ -28,18 +60,15 @@ function get_ids_for_update() {
// Call the global class.
global $wpdb;
- // Set my table name.
- $table_name = $wpdb->prefix . 'comments';
-
// Set up our query.
$query_args = $wpdb->prepare("
SELECT comment_ID
- FROM $table_name
+ FROM $wpdb->comments
WHERE comment_author_IP NOT LIKE '%s'
", esc_attr( $masked_ip ) );
// Process the query.
- $query_run = $wpdb->get_col( $query_args );
+ $query_run = $wpdb->get_col( $query_args ); // phpcs:ignore -- we are skipping the overhead of get_comments.
// Throw the error if we have one.
if ( is_wp_error( $query_run ) ) {
@@ -84,12 +113,9 @@ function replace_single_comment_ip( $comment_id = 0, $masked_ip = '' ) {
// Call the global class.
global $wpdb;
- // Set my table name.
- $table_name = $wpdb->prefix . 'comments';
-
// Run the actual DB update.
- $update_row = $wpdb->update(
- $table_name,
+ $update_row = $wpdb->update( // phpcs:ignore -- we dont want to trigger anything else here.
+ $wpdb->comments,
[ 'comment_author_IP' => $set_new_ip ],
[ 'comment_ID' => absint( $comment_id ) ],
[ '%s' ],
@@ -112,7 +138,7 @@ function replace_single_comment_ip( $comment_id = 0, $masked_ip = '' ) {
*
* @return mixed
*/
-function replace_batch_comment_ips( $comment_ids = array() ) {
+function replace_batch_comment_ips( $comment_ids = [] ) {
// Bail if no comment IDs were provided.
if ( empty( $comment_ids ) ) {
@@ -133,15 +159,12 @@ function replace_batch_comment_ips( $comment_ids = array() ) {
// Call the global class.
global $wpdb;
- // Set my table name.
- $table_name = $wpdb->prefix . 'comments';
-
// Now loop the IDs and run the update.
foreach ( $comment_ids as $comment_id ) {
// Run the actual DB update.
- $update_row = $wpdb->update(
- $table_name,
+ $update_row = $wpdb->update( // phpcs:ignore -- we dont want to trigger anything else here.
+ $wpdb->comments,
[ 'comment_author_IP' => $masked_ip ],
[ 'comment_ID' => absint( $comment_id ) ],
[ '%s' ],
diff --git a/includes/deactivate.php b/includes/deactivate.php
index 48f61d0..4a72d2b 100644
--- a/includes/deactivate.php
+++ b/includes/deactivate.php
@@ -20,8 +20,5 @@ function deactivate() {
// Include our action so that we may add to this later.
do_action( Core\HOOK_PREFIX . 'deactivate_process' );
-
- // And flush our rewrite rules.
- flush_rewrite_rules();
}
register_deactivation_hook( Core\FILE, __NAMESPACE__ . '\deactivate' );
diff --git a/includes/helpers.php b/includes/helpers.php
index 54a9f84..d6e60c6 100644
--- a/includes/helpers.php
+++ b/includes/helpers.php
@@ -36,7 +36,7 @@ function maybe_scrub_enabled( $return_type = 'string' ) {
// Check for the stored "yes" to return.
return ! empty( $set_option ) && 'yes' === sanitize_text_field( $set_option ) ? true : false;
- // And break.
+ // Done.
break;
// Handle my yes / no string return.
@@ -45,7 +45,7 @@ function maybe_scrub_enabled( $return_type = 'string' ) {
// Check for the stored "yes" to return.
return ! empty( $set_option ) && 'yes' === sanitize_text_field( $set_option ) ? 'yes' : 'no';
- // And break.
+ // Done.
break;
}
@@ -66,3 +66,21 @@ function fetch_masked_ip() {
// Confirm it's a valid IP before returning it.
return ! empty( $masked_ip ) && filter_var( $masked_ip, FILTER_VALIDATE_IP ) ? $masked_ip : '127.0.0.1';
}
+
+/**
+ * Get the URL for our settings page with any custom args.
+ *
+ * @param array $args The possible array of args.
+ *
+ * @return string
+ */
+function fetch_settings_url( $args = [] ) {
+
+ // If we have no args, just do the basic link.
+ if ( empty( $args ) ) {
+ return admin_url( 'options-discussion.php' );
+ }
+
+ // Now return it in args.
+ return add_query_arg( $args, admin_url( 'options-discussion.php' ) );
+}
diff --git a/includes/settings-api.php b/includes/settings-api.php
index 7c0cc37..e372556 100644
--- a/includes/settings-api.php
+++ b/includes/settings-api.php
@@ -16,8 +16,43 @@
/**
* Start our engines.
*/
+add_action( 'admin_enqueue_scripts', __NAMESPACE__ . '\load_settings_field_css' );
add_action( 'admin_init', __NAMESPACE__ . '\load_comment_settings' );
+/**
+ * Include a small bit of CSS for our admin.
+ *
+ * @param string $hook_suffix The hook suffix on admin.
+ *
+ * @return void
+ */
+function load_settings_field_css( $hook_suffix ) {
+
+ // Only load this on the comment settings page.
+ if ( empty( $hook_suffix ) || 'options-discussion.php' !== $hook_suffix ) {
+ return;
+ }
+
+ // Set my CSS up.
+ $setup_css = '
+ tr.ip-scrub-bulk-action-wrapper th,
+ tr.ip-scrub-bulk-action-wrapper td {
+ padding-top: 0;
+ }
+
+ tr.ip-scrub-bulk-action-wrapper a.ip-scrub-bulk-admin-button {
+ margin-bottom: 5px;
+ }
+
+ tr.ip-scrub-bulk-action-wrapper p.ip-scrub-bulk-button-explain {
+ margin-top: 0;
+ }
+ ';
+
+ // And add the CSS.
+ wp_add_inline_style( 'common', $setup_css );
+}
+
/**
* Add a checkbox to the comment settings for removing IP addresses.
*
@@ -25,11 +60,27 @@
*/
function load_comment_settings() {
+ // Define the args for the setting registration.
+ $setup_args = [
+ 'type' => 'string',
+ 'show_in_rest' => false,
+ 'default' => 'yes',
+ 'sanitize_callback' => __NAMESPACE__ . '\sanitize_scrub_setting',
+ ];
+
// Add out checkbox with a sanitiation callback.
- register_setting( 'discussion', Core\OPTION_KEY, __NAMESPACE__ . '\sanitize_scrub_setting' );
+ register_setting( 'discussion', Core\OPTION_KEY, $setup_args );
- // Load the actual field itself.
- add_settings_field( 'ip-scrub-enable', __( 'Scrub Comment IPs', 'scrub-comment-author-ip' ), __NAMESPACE__ . '\display_field', 'discussion', 'default' );
+ // Load the actual checkbox field itself.
+ add_settings_field( 'ip-scrub-enable', __( 'Scrub Comment IPs', 'scrub-comment-author-ip' ), __NAMESPACE__ . '\display_field', 'discussion', 'default', [ 'class' => 'ip-scrub-enable-wrapper' ] );
+
+ // Get the amount we could fix.
+ $get_bulk_nums = Database\get_count_for_update();
+
+ // Load the button for the bulk action.
+ if ( ! empty( $get_bulk_nums ) ) {
+ add_settings_field( 'ip-scrub-bulk-action', '', __NAMESPACE__ . '\bulk_action_field', 'discussion', 'default', [ 'class' => 'ip-scrub-bulk-action-wrapper', 'counts' => $get_bulk_nums ] );
+ }
}
/**
@@ -40,16 +91,16 @@ function load_comment_settings() {
function display_field() {
// Set a label with our default IP.
- $set_label = sprintf( __( 'Replace the comment author IP address with %s', 'scrub-comment-author-ip' ), '' . esc_attr( Helpers\fetch_masked_ip() ) . '' );
+ $set_label = sprintf( __( 'Replace the comment author IP address with %s', 'scrub-comment-author-ip' ), '' . esc_html( Helpers\fetch_masked_ip() ) . '' );
// Add a legend output for screen readers.
- echo '';
+ echo '';
// We are wrapping the entire thing in a label.
echo '';
}
+/**
+ * Display a button for the bulk action.
+ *
+ * @return HTML
+ */
+function bulk_action_field( $args ) {
+
+ // Set the bulk args up.
+ $set_bulk_args = [
+ 'ip-scrub-run-bulk' => 'yes',
+ 'ip-scrub-nonce' => wp_create_nonce( 'ip_scrub_bulk' ),
+ ];
+
+ // Set up the link for runniing the bulk update.
+ $set_bulk_link = Helpers\fetch_settings_url( $set_bulk_args );
+
+ // And show the button link.
+ echo '' . esc_html__( 'Bulk Cleanup', 'scrub-comment-author-ip' ) . '';
+
+ // If we have a lot of comments, show the CLI message.
+ // @todo decide on a large number.
+ if ( ! empty( $args['counts'] ) && 200 < absint( $args['counts'] ) ) {
+ echo '
' . esc_html__( 'For sites with a large amount of comments, it is suggested to use the WP-CLI command included with this plugin.', 'scrub-comment-author-ip' ) . '
';
+ }
+}
+
/**
* Make sure the setting is valid.
*
diff --git a/includes/uninstall.php b/includes/uninstall.php
index a3fbf30..e06f6d5 100644
--- a/includes/uninstall.php
+++ b/includes/uninstall.php
@@ -23,8 +23,5 @@ function uninstall() {
// Include our action so that we may add to this later.
do_action( Core\HOOK_PREFIX . 'uninstall_process' );
-
- // And flush our rewrite rules.
- flush_rewrite_rules();
}
register_uninstall_hook( Core\FILE, __NAMESPACE__ . '\uninstall' );
diff --git a/scrub-comment-author-ip.php b/scrub-comment-author-ip.php
index 021a2ca..1ededdd 100644
--- a/scrub-comment-author-ip.php
+++ b/scrub-comment-author-ip.php
@@ -7,7 +7,7 @@
* Author URI: https://andrewnorcross.com
* Text Domain: scrub-comment-author-ip
* Domain Path: /languages
- * Version: 1.0.0
+ * Version: 1.1.0
*
* @package ScrubCommentAuthorIP
*/
@@ -22,7 +22,7 @@
if ( ! defined( 'ABSPATH' ) ) exit;
// Define our version.
-define( __NAMESPACE__ . '\VERS', '1.0.0' );
+define( __NAMESPACE__ . '\VERS', '1.1.0' );
// Plugin root file.
define( __NAMESPACE__ . '\FILE', __FILE__ );
@@ -43,6 +43,7 @@
require_once __DIR__ . '/includes/helpers.php';
require_once __DIR__ . '/includes/settings-api.php';
require_once __DIR__ . '/includes/database.php';
+require_once __DIR__ . '/includes/bulk-process.php';
require_once __DIR__ . '/includes/comment-process.php';
// Check that we have the CLI constant available.