Skip to content

Commit

Permalink
Merge pull request #2 from norcross/feature/bulk-admin-ui
Browse files Browse the repository at this point in the history
adding admin UI for running bulk update
  • Loading branch information
norcross authored Nov 18, 2024
2 parents 837f01f + cd0762e commit d8dc081
Show file tree
Hide file tree
Showing 10 changed files with 349 additions and 37 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 0 additions & 3 deletions includes/activate.php
Original file line number Diff line number Diff line change
Expand Up @@ -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' );
200 changes: 200 additions & 0 deletions includes/bulk-process.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
<?php
/**
* The specific functions for the bulk action.
*
* @package ScrubCommentAuthorIP
*/

// Call our namepsace.
namespace Norcross\ScrubCommentAuthorIP\BulkProcess;

// Set our alias items.
use Norcross\ScrubCommentAuthorIP as Core;
use Norcross\ScrubCommentAuthorIP\Helpers as Helpers;
use Norcross\ScrubCommentAuthorIP\Database as Database;

/**
* Start our engines.
*/
add_action( 'admin_init', __NAMESPACE__ . '\run_admin_bulk_request' );
add_action( 'admin_notices', __NAMESPACE__ . '\admin_bulk_action_notice' );
add_filter( 'removable_query_args', __NAMESPACE__ . '\admin_removable_args' );

/**
* Check for the bulk request coming from the admin.
*
* @return void
*/
function run_admin_bulk_request() {

// Confirm we requested this action.
$confirm_action = filter_input( INPUT_GET, 'ip-scrub-run-bulk', FILTER_SANITIZE_SPECIAL_CHARS ); // phpcs:ignore -- the nonce check is happening after this.

// Make sure it is what we want.
if ( empty( $confirm_action ) || 'yes' !== $confirm_action ) {
return;
}

// Make sure we have a nonce.
$confirm_nonce = filter_input( INPUT_GET, 'ip-scrub-nonce', FILTER_SANITIZE_SPECIAL_CHARS ); // phpcs:ignore -- the nonce check is happening after this.

// Handle the nonce check.
if ( empty( $confirm_nonce ) || ! wp_verify_nonce( $confirm_nonce, 'ip_scrub_bulk' ) ) {

// Let them know they had a failure.
wp_die( esc_html__( 'There was an error validating the nonce.', 'scrub-comment-author-ip' ), esc_html__( 'Scrub Comment IP Bulk Action', 'scrub-comment-author-ip' ), [ 'back_link' => 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 '<div class="notice notice-success is-dismissible">';

// Display the actual message.
echo '<p><strong>' . wp_kses_post( $set_notice ) . '</strong></p>';

// Close the wrapper.
echo '</div>';

// 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 '<div class="notice notice-warning is-dismissible">';

// Display the actual message.
echo '<p><strong>' . wp_kses_post( $set_notice ) . '</strong></p>';

// Close the wrapper.
echo '</div>';

// 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 '<div class="notice notice-error is-dismissible">';

// Display the actual message.
echo '<p><strong>' . wp_kses_post( $set_notice ) . '</strong></p>';

// Close the wrapper.
echo '</div>';

// 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 );
}
55 changes: 39 additions & 16 deletions includes/database.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand All @@ -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 ) ) {
Expand Down Expand Up @@ -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' ],
Expand All @@ -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 ) ) {
Expand All @@ -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' ],
Expand Down
3 changes: 0 additions & 3 deletions includes/deactivate.php
Original file line number Diff line number Diff line change
Expand Up @@ -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' );
22 changes: 20 additions & 2 deletions includes/helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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;
}

Expand All @@ -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' ) );
}
Loading

0 comments on commit d8dc081

Please sign in to comment.