PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 4.0.0
WP 2FA – Two-factor authentication for WordPress v4.0.0
4.0.0 1.7.1 2.0.0 2.0.1 2.1.0 2.2.0 2.2.1 2.3.0 2.4.0 2.4.1 2.4.2 2.5.0 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.8.0 2.9.0 2.9.1 2.9.2 2.9.3 3.0.0 3.0.1 3.1.0 3.1.1 3.1.1.2 trunk 1.2.0 1.3.0 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.6.0 1.6.1 1.6.2 1.7.0
wp-2fa / includes / classes / Admin / Controllers / class-methods.php
wp-2fa / includes / classes / Admin / Controllers Last commit date
class-api-login.php 1 day ago class-endpoints.php 1 day ago class-methods.php 1 day ago class-settings.php 1 day ago index.php 1 day ago
class-methods.php
203 lines
1 <?php
2 /**
3 * Responsible for the plugin methods
4 *
5 * @package wp2fa
6 * @subpackage admin_controllers
7 * @copyright 2026 Melapress
8 * @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
9 * @link https://wordpress.org/plugins/wp-2fa/
10 */
11
12 namespace WP2FA\Admin\Controllers;
13
14 use WP2FA\WP2FA;
15 use WP2FA\Utils\Settings_Utils;
16 use WP2FA\Admin\Controllers\Settings;
17 use WP2FA\Admin\Helpers\Methods_Helper;
18 use WP2FA\Extensions\OutOfBand\Out_Of_Band;
19
20 defined( 'ABSPATH' ) || exit; // Exit if accessed directly.
21
22 /**
23 * Methods class
24 */
25 if ( ! class_exists( '\WP2FA\Admin\Controllers\Methods' ) ) {
26
27 /**
28 * All the methods related functionality must be extracted from this class. Responsible only for global methods data, not the user method related stuff.
29 *
30 * @since 2.2.0
31 */
32 class Methods {
33
34 /**
35 * Holds all the enabled methods in the plugin
36 *
37 * @var array
38 *
39 * @since 2.2.0
40 */
41 private static $enabled_methods = null;
42
43 /**
44 * Works our a list of available 2FA methods. It doesn't include the disabled ones.
45 *
46 * @param string $role - The role to get the methods for. Default is 'global'.
47 *
48 * @return string[]
49 *
50 * @since 2.0.0
51 * @since 2.9.0 - Added role parameter so the methods can be filtered base on the user role.
52 */
53 public static function get_available_2fa_methods( string $role = 'global' ): array {
54 $available_methods = array();
55
56 /**
57 * Add an option for external providers to implement their own 2fa methods and set them as available.
58 *
59 * @param array $available_methods - The array with all the available methods.
60 *
61 * @since 2.0.0
62 */
63 return \apply_filters( WP_2FA_PREFIX . 'available_2fa_methods', $available_methods, $role );
64 }
65
66 /**
67 * Returns array with all the enabled methods in the plugin for the current role
68 *
69 * @param string $role - Role to extract data for.
70 *
71 * @return array
72 *
73 * @since 2.2.0
74 */
75 public static function get_enabled_methods( $role = 'global' ): array {
76 $role = \sanitize_text_field( $role );
77
78 if ( null === self::$enabled_methods || ! isset( self::$enabled_methods[ $role ] ) ) {
79 self::$enabled_methods[ $role ] = array();
80 $providers = Settings::get_providers();
81
82 foreach ( $providers as $provider ) {
83 if ( Settings::is_provider_enabled_for_role( $role, $provider ) ) {
84 $method = Methods_Helper::get_method_by_provider_name( $provider );
85 if ( $method && \method_exists( $method, 'is_secondary' ) && $method::is_secondary() ) {
86 continue;
87 } elseif ( class_exists( '\WP2FA\Extensions\OutOfBand\Out_Of_Band', false ) && Out_Of_Band::METHOD_NAME === $provider ) {
88 self::$enabled_methods[ $role ][ $provider ] = WP2FA::get_wp2fa_setting( 'enable_' . \sanitize_key( $provider ) . '_email', false, false, $role );
89 } else {
90 self::$enabled_methods[ $role ][ $provider ] = WP2FA::get_wp2fa_setting( 'enable_' . \sanitize_key( $provider ), false, false, $role );
91 }
92 }
93 }
94
95 self::$enabled_methods[ $role ] = array_filter( self::$enabled_methods[ $role ] );
96 }
97
98 return self::$enabled_methods;
99 }
100
101 /**
102 * Checks if given method is enabled for given role and returns true or false.
103 *
104 * @param string $provider_name - The name of the method.
105 * @param string $role - The name of the role to check for. Default is 'global.
106 *
107 * @return boolean
108 *
109 * @since 2.9.0
110 */
111 public static function is_method_enabled_for_role( string $provider_name, string $role = 'global' ): bool {
112 $role = \sanitize_text_field( $role );
113
114 if ( ! isset( self::$enabled_methods[ $role ] ) ) {
115 self::get_enabled_methods( $role );
116 }
117
118 if ( isset( self::$enabled_methods[ $role ][ $provider_name ] ) && self::$enabled_methods[ $role ][ $provider_name ] ) {
119 return true;
120 }
121
122 return false;
123 }
124
125 /**
126 * Returns text with the number of methods supported for the given role
127 *
128 * @since 2.2.0
129 *
130 * @return string
131 */
132 public static function get_number_of_methods_text() {
133 return \esc_html__(
134 'There are {available_methods_count} methods available to choose from for 2FA:',
135 'wp-2fa'
136 );
137 }
138
139 /**
140 * Ensures that at least one primary method is enabled in the global policy.
141 * If no primary methods remain after a credential-dependent method is removed,
142 * falls back to enabling TOTP and Email (HOTP) as defaults.
143 *
144 * @return void
145 *
146 * @since 2.8.0
147 */
148 public static function ensure_default_methods_available() {
149 $settings = Settings_Utils::get_option( WP_2FA_POLICY_SETTINGS_NAME );
150
151 if ( ! is_array( $settings ) ) {
152 $settings = array();
153 }
154
155 // Dynamically collect all primary method policy setting keys from registered providers.
156 $has_primary_method = false;
157 $primary_method_keys = array();
158 $providers = Settings::get_providers();
159
160 foreach ( $providers as $class => $slug ) {
161 if ( ! \defined( "$class::POLICY_SETTINGS_NAME" ) ) {
162 continue;
163 }
164 // Skip secondary methods (e.g. Backup Codes, Email Backup).
165 if ( \method_exists( $class, 'is_secondary' ) && $class::is_secondary() ) {
166 continue;
167 }
168 // Skip passkeys — passwordless methods don't count as primary 2FA methods.
169 if ( 'passkeys' === $slug ) {
170 continue;
171 }
172 $primary_method_keys[] = $class::POLICY_SETTINGS_NAME;
173 }
174
175 /**
176 * Filters the list of primary method setting keys to check.
177 *
178 * @param array $primary_method_keys The method setting keys.
179 *
180 * @since 2.8.0
181 */
182 $primary_method_keys = \apply_filters( WP_2FA_PREFIX . 'primary_method_keys', $primary_method_keys );
183
184 foreach ( $primary_method_keys as $method_key ) {
185 if ( ! empty( $settings[ $method_key ] ) ) {
186 $has_primary_method = true;
187 break;
188 }
189 }
190
191 if ( ! $has_primary_method ) {
192 // No primary methods remain — fall back to TOTP and Email.
193 $settings['enable_totp'] = 'enable_totp';
194 $settings['enable_email'] = 'enable_email';
195 WP2FA::update_plugin_settings( $settings );
196 }
197
198 // Reset the cached enabled methods so they are re-evaluated.
199 self::$enabled_methods = null;
200 }
201 }
202 }
203