PluginProbe ʕ •ᴥ•ʔ
Limit Login Attempts Security – Login Security, 2FA, Firewall, Brute Force Prevention / 3.2.4
Limit Login Attempts Security – Login Security, 2FA, Firewall, Brute Force Prevention v3.2.4
3.2.4 3.2.3 3.2.2 3.2.1 3.2.0 trunk 2.0.0 2.1.0 2.10.0 2.10.1 2.11.0 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.14.0 2.15.0 2.15.1 2.15.2 2.16.0 2.17.0 2.17.1 2.17.2 2.17.3 2.17.4 2.18.0 2.19.0 2.19.1 2.19.2 2.2.0 2.20.0 2.20.1 2.20.2 2.20.3 2.20.4 2.20.5 2.20.6 2.21.0 2.21.1 2.22.0 2.22.1 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.25.0 2.25.1 2.25.10 2.25.11 2.25.12 2.25.13 2.25.14 2.25.15 2.25.16 2.25.17 2.25.18 2.25.19 2.25.2 2.25.20 2.25.21 2.25.22 2.25.23 2.25.24 2.25.25 2.25.26 2.25.27 2.25.28 2.25.29 2.25.3 2.25.4 2.25.5 2.25.6 2.25.7 2.25.8 2.25.9 2.26.0 2.26.1 2.26.10 2.26.11 2.26.12 2.26.13 2.26.14 2.26.15 2.26.16 2.26.17 2.26.18 2.26.19 2.26.2 2.26.20 2.26.21 2.26.22 2.26.23 2.26.24 2.26.25 2.26.26 2.26.27 2.26.28 2.26.3 2.26.4 2.26.5 2.26.6 2.26.7 2.26.8 2.26.9 2.3.0 2.4.0 2.5.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.8.0 2.8.1 2.9.0 3.0.0 3.0.1 3.0.2 3.1.0
limit-login-attempts-reloaded / core / integrations / WooCommerceIntegration.php
limit-login-attempts-reloaded / core / integrations Last commit date
BaseIntegration.php 2 weeks ago IntegrationInterface.php 2 weeks ago IntegrationManager.php 2 weeks ago MemberPressIntegration.php 2 weeks ago WooCommerceIntegration.php 2 weeks ago
WooCommerceIntegration.php
255 lines
1 <?php
2
3 namespace LLAR\Core\Integrations;
4
5 if ( ! defined( 'ABSPATH' ) ) {
6 exit;
7 }
8
9 class WooCommerceIntegration extends BaseIntegration {
10
11 /**
12 * Get the name of the plugin this integration supports
13 *
14 * @return string
15 */
16 public function get_plugin_name() {
17 return 'WooCommerce';
18 }
19
20 /**
21 * Check if WooCommerce plugin is active
22 *
23 * @return bool
24 */
25 public static function is_plugin_active() {
26 return function_exists( 'is_account_page' ) && function_exists( 'wc_add_notice' );
27 }
28
29 /**
30 * Register all hooks and filters for WooCommerce
31 *
32 * @return void
33 */
34 public function register_hooks() {
35 if ( ! static::is_plugin_active() ) {
36 return;
37 }
38
39 // Add notices to woocommerce login page
40 add_action( 'wp_head', array( $this, 'add_wc_notices' ) );
41
42 // Protect WooCommerce registration
43 add_action( 'woocommerce_register_post', array( $this, 'wc_register_post_handler' ), 10, 3 );
44 add_filter( 'woocommerce_registration_errors', array( $this, 'wc_registration_errors_handler' ), 10, 3 );
45 }
46
47 /**
48 * Check if this is WooCommerce login page
49 *
50 * @return bool
51 */
52 public function is_login_page() {
53 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Only checking for presence, not processing
54 return static::is_plugin_active() && is_account_page() && isset( $_POST['username'] );
55 }
56
57 /**
58 * Get login credentials from the request
59 *
60 * @return array|null
61 */
62 public function get_login_credentials() {
63 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Reading POST data for validation, nonce checked by WooCommerce
64 if ( ! isset( $_POST['username'] ) || ! isset( $_POST['password'] ) ) {
65 return null;
66 }
67
68 return array(
69 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Reading POST data for validation, nonce checked by WooCommerce
70 'username' => sanitize_text_field( wp_unslash( $_POST['username'] ) ),
71 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Reading POST data for validation, nonce checked by WooCommerce
72 'password' => wp_unslash( $_POST['password'] ), // Password should not be sanitized, but needs wp_unslash() to remove magic quotes
73 );
74 }
75
76 /**
77 * Get login identifier for WooCommerce auth flow.
78 *
79 * @return string
80 */
81 public function get_login_identifier() {
82 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Read-only access to request data
83 if ( ! isset( $_REQUEST['username'] ) ) {
84 return '';
85 }
86
87 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Read-only access to request data
88 return sanitize_text_field( wp_unslash( $_REQUEST['username'] ) );
89 }
90
91 /**
92 * Display error message on WooCommerce login page
93 *
94 * @param string $message Error message
95 * @return void
96 */
97 public function display_error( $message ) {
98 if ( static::is_plugin_active() && is_account_page() ) {
99 wc_add_notice( $message, 'error' );
100 }
101 }
102
103 /**
104 * Check if this is WooCommerce registration page
105 *
106 * @return bool
107 */
108 public function is_registration_page() {
109 // WooCommerce uses standard WordPress registration fields
110 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Only checking for presence, not processing
111 $result = static::is_plugin_active() && is_account_page() && ( isset( $_POST['user_login'] ) || isset( $_POST['user_email'] ) );
112 return $result;
113 }
114
115 /**
116 * Get registration data from the request
117 *
118 * @return array|null
119 */
120 public function get_registration_data() {
121 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Reading POST data for validation, nonce checked by WooCommerce
122 if ( empty( $_POST['user_login'] ) && empty( $_POST['user_email'] ) ) {
123 return null;
124 }
125
126 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Reading POST data for validation, nonce checked by WooCommerce
127 $user_login = isset( $_POST['user_login'] ) ? sanitize_text_field( wp_unslash( $_POST['user_login'] ) ) : '';
128 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Reading POST data for validation, nonce checked by WooCommerce
129 // Note: sanitize_email() is used here for form data retrieval, but sanitize_user() is used in wc_register_post_handler()
130 // for API calls to match the original API behavior
131 $user_email = isset( $_POST['user_email'] ) ? sanitize_email( wp_unslash( $_POST['user_email'] ) ) : '';
132
133 // Only return if at least one field is present
134 if ( empty( $user_login ) && empty( $user_email ) ) {
135 return null;
136 }
137
138 return array(
139 'username' => $user_login,
140 'email' => $user_email,
141 );
142 }
143
144 /**
145 * Display error message on WooCommerce registration page
146 *
147 * @param string $message Error message
148 * @return void
149 */
150 public function display_registration_error( $message ) {
151 if ( static::is_plugin_active() && is_account_page() ) {
152 wc_add_notice( $message, 'error' );
153 }
154 }
155
156 /**
157 * Errors on WooCommerce account page
158 */
159 public function add_wc_notices() {
160 global $limit_login_just_lockedout, $limit_login_nonempty_credentials, $limit_login_my_error_shown;
161
162 if ( ! $limit_login_nonempty_credentials ) {
163 return;
164 }
165
166 // Prevent duplicate error messages if already shown elsewhere
167 if ( ! empty( $limit_login_my_error_shown ) ) {
168 return;
169 }
170
171 /*
172 * During lockout we do not want to show any other error messages (like
173 * unknown user or empty password).
174 */
175 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Only checking POST for display logic, not processing
176 if ( empty( $_POST ) && ! $this->is_login_allowed() && ! $limit_login_just_lockedout ) {
177 if ( is_account_page() ) {
178 wc_add_notice( $this->get_error_message(), 'error' );
179 // Mark error as shown to prevent duplicate messages
180 $limit_login_my_error_shown = true;
181 }
182 }
183 }
184
185 /**
186 * For WooCommerce registration
187 * Check registration attempt before WooCommerce processes it
188 *
189 * @param string $username Username
190 * @param string $user_email User email
191 * @param WP_Error $errors Error object
192 * @return void
193 */
194 public function wc_register_post_handler( $username, $user_email, $errors ) {
195 if ( ! $this->is_registration_limited() ) {
196 return;
197 }
198
199 if ( empty( $username ) && empty( $user_email ) ) {
200 return;
201 }
202
203 // Exit only if BOTH fields are invalid (empty or invalid)
204 // Continue if at least one field is valid
205 // Logic: exit if (username is invalid) AND (email is invalid)
206 $username_invalid = empty( $username ) || ! validate_username( $username );
207 $email_invalid = empty( $user_email ) || ! is_email( $user_email );
208 if ( $username_invalid && $email_invalid ) {
209 return;
210 }
211
212 // Use sanitize_user() for username and sanitize_email() for email to match original API behavior
213 // This matches the behavior in llar_submit_login_form_register()
214 $user_login_sanitize = sanitize_user( $username );
215 $user_email_sanitize = sanitize_email( $user_email );
216
217 // Check any non-empty
218 $check_combo = ! empty( $user_login_sanitize ) ? $user_login_sanitize : $user_email_sanitize;
219
220 $response = $this->check_registration_api( $check_combo );
221
222 // If $user_login is not empty, we will also check $user_email
223 if ( ! empty( $user_login_sanitize ) && 'deny' !== $response['result'] ) {
224 if ( empty( $user_email ) || ! is_email( $user_email ) ) {
225 return;
226 }
227
228 $response = $this->check_registration_api( $user_email_sanitize );
229 }
230
231 if ( 'deny' === $response['result'] ) {
232 // Set the marker and the error
233 $this->llar_instance->user_blocking = true;
234 $this->llar_instance->error_messages = __( 'Registration is currently disabled.', 'limit-login-attempts-reloaded' );
235 }
236 }
237
238 /**
239 * Correcting errors in the presence of a registration prohibition marker for WooCommerce
240 *
241 * @param WP_Error $errors Error object
242 * @param string $username Username
243 * @param string $user_email User email
244 * @return WP_Error
245 */
246 public function wc_registration_errors_handler( $errors, $username, $user_email ) {
247 // Checking the marker
248 if ( $this->llar_instance->user_blocking ) {
249 $errors->add( 'user_blocking', $this->llar_instance->error_messages );
250 }
251
252 return $errors;
253 }
254 }
255