Hi @kurtnuimage,
It seems the woocommerce_process_login_errors is not an action but a filter. The code in your hooked callback (add_wc_process_login_errors) may not be correct.
Furthermore it seems you can also use the WordPress Core login_errors filter.
+++ To prevent any confusion, I’m not SolidWP +++
-
This reply was modified 8 months, 4 weeks ago by
nlpro.
Thread Starter
nukurt
(@kurtnuimage)
Hi @nlpro
Thanks for the response, you are right it is actually a filter instead. That is actually something i noticed as well.
The problem with using the woocommerce_process_login_errors filter is that it seems to fire before Solid Security, so using the filter means that login attempts no longer seem to be logged into the wp_itsec_logs table.
I know you’re not Solid Security so i understand if you don’t know, but i guess i need to know at which point Solid Security writes to the database, so i can use a filter after this point and return my error message.
Hello,
Apologies for the delay here!
This code is untested so please try this on a staging/development site before pushing it live. This should help get you pointed in the right direction:
<?php
/**
* WooCommerce: show Solid Security "attempts remaining" after a real failed login.
* Place in wp-content/mu-plugins/attempts-remaining.php (preferred) or your theme’s functions.php
*/
add_action( 'wp_login_failed', function ( $username, $error ) {
// Only show on WooCommerce flows where notices are displayed.
if ( ! function_exists( 'wc_add_notice' ) ) {
return;
}
// Solid Security classes must be available.
if ( ! class_exists( 'ITSEC_Modules' ) || ! class_exists( 'ITSEC_Lib' ) ) {
return;
}
$settings = ITSEC_Modules::get_settings( 'brute-force' );
$host_limit = isset( $settings['max_attempts_host'] ) ? (int) $settings['max_attempts_host'] : 0;
$user_limit = isset( $settings['max_attempts_user'] ) ? (int) $settings['max_attempts_user'] : 0;
$period_min = isset( $settings['check_period'] ) ? (int) $settings['check_period'] : 0;
// If both limits are effectively disabled, skip.
if ( $host_limit <= 0 && $user_limit <= 0 ) {
return;
}
global $wpdb;
$table = $wpdb->base_prefix . 'itsec_logs';
$since = gmdate( 'Y-m-d H:i:s', time() - ( $period_min * 60 ) );
// Use Solid Security’s IP helper so proxies/CDN are respected (configure Proxy Detection in Security > Settings > Global).
$ip = ITSEC_Lib::get_ip();
// Count failures for this host (IP) in the window.
$host_used = 0;
if ( $host_limit > 0 ) {
$host_used = (int) $wpdb->get_var(
$wpdb->prepare(
"SELECT COUNT(*)
FROM {$table}
WHERE module = %s
AND code LIKE 'invalid-login%%'
AND remote_ip = %s
AND init_timestamp > %s",
'brute_force', $ip, $since
)
);
}
$host_remaining = ( $host_limit > 0 ) ? max( 0, $host_limit - $host_used ) : PHP_INT_MAX;
// Count failures for this specific user (if it exists) in the window.
$user_remaining = PHP_INT_MAX;
if ( $user_limit > 0 ) {
$user = get_user_by( is_email( $username ) ? 'email' : 'login', $username );
if ( $user instanceof WP_User ) {
$user_used = (int) $wpdb->get_var(
$wpdb->prepare(
"SELECT COUNT(*)
FROM {$table}
WHERE module = %s
AND code = %s
AND init_timestamp > %s",
'brute_force',
'invalid-login::user-' . $user->ID,
$since
)
);
$user_remaining = max( 0, $user_limit - $user_used );
}
}
$remaining = min( $host_remaining, $user_remaining );
// If at least one limit is active, show a notice.
if ( PHP_INT_MAX !== $remaining ) {
/* translators: 1: number remaining, 2: "s" plural suffix (or empty), 3: minutes in window */
$message = sprintf(
__( 'Heads up: You have %1$d login attempt%2$s remaining before a temporary lockout (resets after %3$d minutes).', 'your-textdomain' ),
$remaining,
( 1 === (int) $remaining ) ? '' : 's',
$period_min
);
// Use a neutral notice; switch to 'error' if you want it red.
wc_add_notice( $message, 'notice' );
}
}, 10, 2 );
Let me know if you run into any issues!
Thread Starter
nukurt
(@kurtnuimage)
Hi @bwbama,
This code seems to work great thank you!
The one minor adjustment i made was to not show the notice if the IP is found in the authorized IP list, but this is done now.
Thanks for the help!