*/ const MODULE_ROW_IDS = [ 'block_login' => 'block-login-lockouts', 'two_factor_authentication' => 'two-factor-authentication', 'custom_login_url' => 'custom-login-url', ]; /** * One line on what is not covered while a module is off. A security module * without an entry here gets a generic line, so a newly added module still * appears. * * @return array */ public static function coverage_lines(): array { return [ 'block_login' => __( 'Repeated failed logins are not blocked, so passwords can be guessed without limit.', 'admin-optimizer' ), 'two_factor_authentication' => __( 'Logins need only a password, so a stolen password is enough to get in.', 'admin-optimizer' ), 'custom_login_url' => __( 'The login page stays at wp-login.php, a common target for bots.', 'admin-optimizer' ), ]; } /** * Off rows for disabled security modules. * * @param string[] $existing_row_ids Ids of rows already collected. * * @return array */ public static function rows( array $existing_row_ids ): array { $rows = []; $priority = self::OFF_PRIORITY; foreach ( Module_Registry::get_modules_by_section( 'security' ) as $module ) { if ( Module_Registry::MODULE !== ( $module['classification'] ?? '' ) || ! empty( $module['retired'] ) || ! Module_Registry::is_toggleable( $module['id'] ) || Module_Registry::is_enabled( $module['id'] ) ) { continue; } $spoken_for = self::MODULE_ROW_IDS[ $module['id'] ] ?? ''; if ( '' !== $spoken_for && in_array( $spoken_for, $existing_row_ids, true ) ) { continue; } $rows[] = self::build_off_row( $module, Module_Registry::get_module_url( $module['id'] ), $priority++ ); } return $rows; } /** * Build one Off row. Pure, so the shape can be tested. * * @param array $module Registry entry (`id`, `slug`, `name`). * @param string $url Link to the module's own screen, where it can be turned on. * @param int $priority Sort priority. * * @return array */ public static function build_off_row( array $module, string $url, int $priority ): array { $lines = self::coverage_lines(); return [ 'id' => 'off-' . ( $module['slug'] ?? $module['id'] ), 'label' => (string) $module['name'], 'status' => 'off', 'message' => $lines[ $module['id'] ] ?? __( 'This module is turned off.', 'admin-optimizer' ), 'url' => $url, 'link_label' => __( 'Turn on', 'admin-optimizer' ), 'group' => self::GROUP, 'priority' => $priority, ]; } /** * The locked "File monitoring: Pro" row, or null when Pro is active (Pro * then reports file monitoring itself). * * @return array|null */ public static function pro_lock_row(): ?array { if ( Module_Registry::is_pro_active() ) { return null; } return [ 'id' => 'file-monitoring-pro', 'label' => __( 'File monitoring', 'admin-optimizer' ), 'message' => __( 'Scheduled file-integrity scans and alerts are part of Admin Optimizer Pro.', 'admin-optimizer' ), 'url' => ao_get_upgrade_url( 'security-monitor-site-health' ), 'link_label' => __( 'Upgrade to Pro', 'admin-optimizer' ), 'group' => self::GROUP, 'status' => 'off', 'priority' => self::LOCK_PRIORITY, 'locked' => true, ]; } }