| @@ -6,8 +6,9 @@ | ||
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | 8 | namespace WP_Defender\Controller; |
| 9 | 9 | |
| 10 | +use Countable; | |
| 10 | 11 | use WP_Defender\Event; |
| 11 | 12 | use Calotes\Component\Request; |
| 12 | 13 | use Calotes\Component\Response; |
| 13 | 14 | use WP_Defender\Integrations\Woocommerce; |
| @@ -41,8 +42,15 @@ | ||
| 41 | 42 | */ |
| 42 | 43 | private ?Password_Protection $helper; |
| 43 | 44 | |
| 44 | 45 | /** |
| 46 | + * WooCommerce integration instance. | |
| 47 | + * | |
| 48 | + * @var Woocommerce|null | |
| 49 | + */ | |
| 50 | + private ?Woocommerce $woo; | |
| 51 | + | |
| 52 | + /** | |
| 45 | 53 | * Initializes the model and service, registers routes, and sets up scheduled events if the model is active. |
| 46 | 54 | */ |
| 47 | 55 | public function __construct() { |
| 48 | 56 | $this->model = wd_di()->get( Settings::class ); |
| @@ -47,46 +55,78 @@ | ||
| 47 | 55 | public function __construct() { |
| 48 | 56 | $this->model = wd_di()->get( Settings::class ); |
| 49 | 57 | $this->service = wd_di()->get( Service::class ); |
| 50 | 58 | $this->helper = wd_di()->get( Password_Protection::class ); |
| 51 | - add_filter( 'wp_defender_advanced_tools_data', array( $this, 'script_data' ) ); | |
| 59 | + $this->woo = wd_di()->get( Woocommerce::class ); | |
| 52 | 60 | $this->register_routes(); |
| 53 | 61 | if ( $this->model->is_active() ) { |
| 54 | - // Update site url on sub-site when MaskLogin is disabled. | |
| 55 | - if ( | |
| 56 | - is_multisite() && ! is_main_site() | |
| 57 | - && ! wd_di()->get( \WP_Defender\Model\Setting\Mask_Login::class )->is_active() | |
| 58 | - ) { | |
| 59 | - add_filter( 'network_site_url', array( $this->helper, 'filter_site_url' ), 100, 2 ); | |
| 60 | - } | |
| 61 | - remove_action( 'user_profile_update_errors', 'slt_fsp_validate_profile_update', 0 ); | |
| 62 | - remove_action( 'resetpass_form', 'slt_fsp_validate_resetpass_form', 10 ); | |
| 63 | - if ( is_admin() ) { | |
| 64 | - add_action( 'admin_enqueue_scripts', array( $this->service, 'scripts' ) ); | |
| 65 | - add_action( 'user_profile_update_errors', array( $this->service, 'on_profile_update' ), 100, 3 ); | |
| 66 | - } | |
| 67 | - add_action( 'login_enqueue_scripts', array( $this->service, 'scripts' ) ); | |
| 68 | - add_action( 'wp_enqueue_scripts', array( $this->service, 'scripts' ) ); | |
| 69 | - add_action( 'validate_password_reset', array( $this->service, 'on_password_reset' ), 100, 2 ); | |
| 70 | - add_action( 'wp_authenticate_user', array( $this->service, 'during_authentication' ), 100, 2 ); | |
| 71 | - add_filter( 'random_password', array( $this->service, 'generate_password' ), 10, 2 ); | |
| 72 | - if ( wd_di()->get( Woocommerce::class )->is_wc_login_context() ) { | |
| 73 | - add_filter( 'woocommerce_reset_password_message', array( $this->service, 'add_woocommerce_error_message' ) ); | |
| 74 | - } | |
| 62 | + $this->setup_hooks(); | |
| 75 | 63 | } |
| 76 | 64 | } |
| 77 | 65 | |
| 78 | 66 | /** |
| 79 | - * Provide data to the frontend via localized script. | |
| 80 | - * | |
| 81 | - * @param array $data Data collection is ready to passed. | |
| 82 | - * | |
| 83 | - * @return array Modified data array with added this controller data. | |
| 67 | + * Set up core WordPress hooks for strong password functionality. | |
| 68 | + * These hooks work independently of WooCommerce settings. | |
| 84 | 69 | */ |
| 85 | - public function script_data( array $data ): array { | |
| 86 | - $data['strong_password'] = $this->data_frontend(); | |
| 70 | + private function setup_hooks() { | |
| 71 | + // Remove conflicting plugins. | |
| 72 | + remove_action( 'user_profile_update_errors', 'slt_fsp_validate_profile_update', 0 ); | |
| 73 | + remove_action( 'resetpass_form', 'slt_fsp_validate_resetpass_form', 10 ); | |
| 87 | 74 | |
| 88 | - return $data; | |
| 75 | + // Admin hooks. | |
| 76 | + if ( is_admin() ) { | |
| 77 | + add_action( 'admin_enqueue_scripts', array( $this->service, 'scripts' ) ); | |
| 78 | + add_action( 'user_profile_update_errors', array( $this->service, 'on_profile_update' ), 100, 3 ); | |
| 79 | + } | |
| 80 | + | |
| 81 | + // Core WordPress authentication and password hooks. | |
| 82 | + add_action( 'login_enqueue_scripts', array( $this->service, 'scripts' ) ); | |
| 83 | + add_action( 'validate_password_reset', array( $this->service, 'on_password_reset' ), 100, 2 ); | |
| 84 | + add_action( 'wp_authenticate_user', array( $this->service, 'during_core_authentication' ), 100, 2 ); | |
| 85 | + add_filter( 'random_password', array( $this->service, 'generate_password' ), 10, 2 ); | |
| 86 | + | |
| 87 | + // WooCommerce-specific hooks — each gated on its own form setting. | |
| 88 | + if ( | |
| 89 | + $this->woo->is_activated() && | |
| 90 | + isset( $this->model->plugins['woocommerce'] ) && | |
| 91 | + $this->model->plugins['woocommerce'] | |
| 92 | + ) { | |
| 93 | + $woo_forms = $this->model->forms['woocommerce'] ?? array(); | |
| 94 | + | |
| 95 | + if ( array() !== $woo_forms ) { | |
| 96 | + add_action( 'wp_enqueue_scripts', array( $this->service, 'scripts' ) ); | |
| 97 | + add_action( | |
| 98 | + 'woocommerce_save_account_details_errors', | |
| 99 | + array( $this->service, 'on_woo_account_update' ), | |
| 100 | + 100, | |
| 101 | + 2 | |
| 102 | + ); | |
| 103 | + } | |
| 104 | + | |
| 105 | + if ( in_array( Woocommerce::WOO_REGISTER_FORM, $woo_forms, true ) ) { | |
| 106 | + add_filter( | |
| 107 | + 'woocommerce_process_registration_errors', | |
| 108 | + array( $this->service, 'during_woo_registration' ), | |
| 109 | + 100 | |
| 110 | + ); | |
| 111 | + } | |
| 112 | + | |
| 113 | + if ( in_array( Woocommerce::WOO_LOGIN_FORM, $woo_forms, true ) || in_array( Woocommerce::WOO_CHECKOUT_FORM, $woo_forms, true ) ) { | |
| 114 | + add_filter( | |
| 115 | + 'woocommerce_process_login_errors', | |
| 116 | + array( $this->service, 'during_woo_authentication' ), | |
| 117 | + 100, | |
| 118 | + 3 | |
| 119 | + ); | |
| 120 | + } | |
| 121 | + | |
| 122 | + if ( in_array( Woocommerce::WOO_LOST_PASSWORD_FORM, $woo_forms, true ) ) { | |
| 123 | + add_filter( | |
| 124 | + 'woocommerce_reset_password_message', | |
| 125 | + array( $this->service, 'add_woocommerce_error_message' ) | |
| 126 | + ); | |
| 127 | + } | |
| 128 | + } | |
| 89 | 129 | } |
| 90 | 130 | |
| 91 | 131 | /** |
| 92 | 132 | * All the variables that we will show on frontend, both in the main page, or dashboard widget. |
| @@ -95,11 +135,13 @@ | ||
| 95 | 135 | */ |
| 96 | 136 | public function data_frontend(): array { |
| 97 | 137 | return array_merge( |
| 98 | 138 | array( |
| 99 | - 'is_active' => $this->model->is_active(), | |
| 100 | - 'model' => $this->model->export(), | |
| 101 | - 'all_roles' => wp_list_pluck( get_editable_roles(), 'name' ), | |
| 139 | + 'is_active' => $this->model->is_active(), | |
| 140 | + 'model' => $this->model->export(), | |
| 141 | + 'all_roles' => wp_list_pluck( get_editable_roles(), 'name' ), | |
| 142 | + 'woo_forms' => Woocommerce::get_forms(), | |
| 143 | + 'is_woo_active' => wd_di()->get( Woocommerce::class )->is_activated(), | |
| 102 | 144 | ), |
| 103 | 145 | $this->dump_routes_and_nonces() |
| 104 | 146 | ); |
| 105 | 147 | } |
| @@ -121,9 +163,9 @@ | ||
| 121 | 163 | |
| 122 | 164 | $response = array( |
| 123 | 165 | 'auto_close' => true, |
| 124 | 166 | ); |
| 125 | - if ( $this->model->enabled && empty( $this->model->user_roles ) ) { | |
| 167 | + if ( $this->model->enabled && array() === $this->model->user_roles ) { | |
| 126 | 168 | // we need to control this message in front. |
| 127 | 169 | $response['warning'] = sprintf( |
| 128 | 170 | /* translators: 1. Open tag. 2. Close tag. */ |
| 129 | 171 | esc_html__( 'You need to check at least one of the %1$sStrong Passwords checks preferences below%2$s and save your settings to enable Strong Password Protection.', 'defender-security' ), |
| @@ -135,9 +177,9 @@ | ||
| 135 | 177 | } |
| 136 | 178 | |
| 137 | 179 | if ( $this->maybe_track() ) { |
| 138 | 180 | $prev_data = $this->model->get_old_settings(); |
| 139 | - if ( ! empty( $prev_data ) ) { | |
| 181 | + if ( array() !== $prev_data ) { | |
| 140 | 182 | if ( $this->model->enabled && ! $prev_data['enabled'] ) { |
| 141 | 183 | $need_track = true; |
| 142 | 184 | $event = 'def_feature_activated'; |
| 143 | 185 | } elseif ( ! $this->model->enabled && $prev_data['enabled'] ) { |
| @@ -180,10 +222,8 @@ | ||
| 180 | 222 | /** |
| 181 | 223 | * Import the data of other source into this, it can be when HUB trigger the import, or user apply a preset. |
| 182 | 224 | * |
| 183 | 225 | * @param array $data Data from other source. |
| 184 | - * | |
| 185 | - * @return null|void | |
| 186 | 226 | */ |
| 187 | 227 | public function import_data( array $data ) { |
| 188 | 228 | $this->model->import( $data ); |
| 189 | 229 | if ( $this->model->validate() ) { |
| @@ -192,10 +232,8 @@ | ||
| 192 | 232 | } |
| 193 | 233 | |
| 194 | 234 | /** |
| 195 | 235 | * Remove all settings, configs generated in this container runtime. |
| 196 | - * | |
| 197 | - * @return mixed | |
| 198 | 236 | */ |
| 199 | 237 | public function remove_settings() { |
| 200 | 238 | } |
| 201 | 239 | |
| @@ -211,8 +249,33 @@ | ||
| 211 | 249 | */ |
| 212 | 250 | public function export_strings(): array { |
| 213 | 251 | return array( |
| 214 | 252 | $this->model->is_active() ? esc_html__( 'Active', 'defender-security' ) : esc_html__( 'Inactive', 'defender-security' ), |
| 253 | + ); | |
| 254 | + } | |
| 255 | + | |
| 256 | + /** | |
| 257 | + * Generates configuration strings based on the provided configuration. | |
| 258 | + * | |
| 259 | + * @param mixed $config The configuration data. | |
| 260 | + * | |
| 261 | + * @return array Returns an array of configuration strings. | |
| 262 | + */ | |
| 263 | + public function config_strings( $config ): array { | |
| 264 | + $is_enabled = isset( $config['enabled'] ) ? (bool) $config['enabled'] : false; | |
| 265 | + if ( | |
| 266 | + ! $is_enabled || | |
| 267 | + ! isset( $config['user_roles'] ) || | |
| 268 | + ! is_array( $config['user_roles'] ) || | |
| 269 | + array() === $config['user_roles'] | |
| 270 | + ) { | |
| 271 | + return array( esc_html__( 'Inactive', 'defender-security' ) ); | |
| 272 | + } | |
| 273 | + | |
| 274 | + return array( | |
| 275 | + $is_enabled && ( is_array( $config['user_roles'] ) || $config['user_roles'] instanceof Countable ? count( $config['user_roles'] ) : 0 ) > 0 | |
| 276 | + ? esc_html__( 'Active', 'defender-security' ) | |
| 277 | + : esc_html__( 'Inactive', 'defender-security' ), | |
| 215 | 278 | ); |
| 216 | 279 | } |
| 217 | 280 | |
| 218 | 281 | /** |