Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
84.31% |
86 / 102 |
|
40.00% |
2 / 5 |
CRAP | |
0.00% |
0 / 1 |
Settings_Payments | |
84.31% |
86 / 102 |
|
40.00% |
2 / 5 |
14.76 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
record_page_visit_time | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
42 | |||
add_section | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
settings | |
98.36% |
60 / 61 |
|
0.00% |
0 / 1 |
3 | |||
print_attempts_per_interval_settings_field | |
100.00% |
24 / 24 |
|
100.00% |
1 / 1 |
3 |
1 | <?php |
2 | /** |
3 | * Settings page to display in WooCommerce. |
4 | * |
5 | * @see /wp-admin/admin.php?page=wc-settings&tab=advanced§ion=checkout-rate-limiting |
6 | * |
7 | * @author BrianHenryIE <BrianHenryIE@gmail.com> |
8 | * @link https://BrianHenryIE.com |
9 | * @since 1.0.0 |
10 | * @package brianhenryie/bh-wc-checkout-rate-limiter |
11 | */ |
12 | |
13 | namespace BrianHenryIE\Checkout_Rate_Limiter\WooCommerce; |
14 | |
15 | use BrianHenryIE\Checkout_Rate_Limiter\Settings_Interface; |
16 | use Psr\Log\LoggerAwareTrait; |
17 | use Psr\Log\LoggerInterface; |
18 | use Psr\Log\LogLevel; |
19 | use WC_Admin_Settings; |
20 | |
21 | /** |
22 | * * Adds the settings section to WooCommerce, under Payments. |
23 | * * Provides the list of settings. |
24 | * * Contains a custom setting type for printing two integer input boxes alongside each other. |
25 | * |
26 | * Class Settings_Payments |
27 | * |
28 | * @package brianhenryie/bh-wc-checkout-rate-limiter |
29 | */ |
30 | class Settings_Payments { |
31 | |
32 | use LoggerAwareTrait; |
33 | |
34 | /** |
35 | * The plugin's settings. |
36 | * |
37 | * @var Settings_Interface |
38 | */ |
39 | protected Settings_Interface $settings; |
40 | |
41 | /** |
42 | * Instantiate. |
43 | * |
44 | * @param Settings_Interface $settings The plugin settings. |
45 | * @param LoggerInterface $logger PSR logger. |
46 | */ |
47 | public function __construct( Settings_Interface $settings, LoggerInterface $logger ) { |
48 | $this->settings = $settings; |
49 | $this->setLogger( $logger ); |
50 | } |
51 | |
52 | /** |
53 | * Record the last visited time of the settings page so the admin notice can be hidden. |
54 | * |
55 | * @hooked current_screen |
56 | */ |
57 | public function record_page_visit_time(): void { |
58 | |
59 | if ( ! function_exists( 'wc_get_current_admin_url' ) ) { |
60 | return; |
61 | } |
62 | |
63 | $wc_admin_url = wc_get_current_admin_url(); |
64 | |
65 | if ( empty( $wc_admin_url ) ) { |
66 | return; |
67 | } |
68 | |
69 | $url_parts = wp_parse_url( $wc_admin_url ); |
70 | |
71 | if ( empty( $url_parts['query'] ) ) { |
72 | return; |
73 | } |
74 | |
75 | $query_parts = array(); |
76 | wp_parse_str( $url_parts['query'], $query_parts ); |
77 | |
78 | if ( ! isset( $query_parts['section'] ) || 'checkout-rate-limiting' !== $query_parts['section'] ) { |
79 | return; |
80 | } |
81 | |
82 | update_option( 'bh_wc_checkout_rate_limiter_visited_settings_time', time() ); |
83 | } |
84 | |
85 | /** |
86 | * Add the settings section to WordPress/WooCommerce/Settings/Advanced/Rate Limiting |
87 | * |
88 | * /wp-admin/admin.php?page=wc-settings&tab=advanced§ion=checkout-rate-limiting |
89 | * |
90 | * @hooked woocommerce_get_sections_checkout |
91 | * @see \WC_Settings_Advanced::get_sections() |
92 | * |
93 | * @param array<string, string> $sections The horizontal subsections in the WooCommerce settings. |
94 | * @return array<string, string> |
95 | */ |
96 | public function add_section( array $sections ): array { |
97 | |
98 | $sections['checkout-rate-limiting'] = 'Rate Limiting'; |
99 | |
100 | return $sections; |
101 | } |
102 | |
103 | /** |
104 | * Adds the settings: |
105 | * * Title + description |
106 | * * Enable/disable |
107 | * * Rate limits: attempts per interval |
108 | * * Log level |
109 | * |
110 | * * Empty cart?! |
111 | * |
112 | * @hooked woocommerce_get_settings_checkout |
113 | * @see \WC_Settings_Advanced::get_settings() |
114 | * |
115 | * @param array<int|string, array<string, mixed>> $settings WC_Settings_API settings fields. |
116 | * @param string $current_section The slug of the current horizontal sub-section. |
117 | * |
118 | * @return array<int|string, array<string, mixed>> |
119 | */ |
120 | public function settings( array $settings, string $current_section ): array { |
121 | |
122 | if ( 'checkout-rate-limiting' !== $current_section ) { |
123 | return $settings; |
124 | } |
125 | |
126 | $settings[] = array( |
127 | 'title' => 'Checkout Rate-Limiting', |
128 | 'type' => 'title', |
129 | 'desc' => 'Each time a customer clicks "Place Order", their IP address is checked to see how many times they have already tried to place an order recently.', |
130 | 'id' => 'checkout-rate-limiting', |
131 | ); |
132 | |
133 | // TODO: Add link to GitHub. Add link to logs. |
134 | |
135 | $settings['bh_wc_checkout_rate_limiter_checkout_rate_limiting_enabled'] = array( |
136 | 'title' => __( 'Limit checkout attempts', 'bh-wc-checkout-rate-limiter' ), |
137 | 'desc' => __( 'When enabled, each IP address can only make as many attempts at payment as specified below.', 'bh-wc-checkout-rate-limiter' ), |
138 | 'id' => 'bh_wc_checkout_rate_limiter_checkout_rate_limiting_enabled', |
139 | 'type' => 'checkbox', |
140 | 'default' => 'yes', |
141 | ); |
142 | |
143 | // Attempts per interval. |
144 | $settings['bh_wc_checkout_rate_limiter_allowed_attempts_per_interval_1'] = array( |
145 | 'title' => '', |
146 | 'id' => 'bh_wc_checkout_rate_limiter_allowed_attempts_per_interval_1', |
147 | 'type' => 'attempts_per_interval', |
148 | 'default' => array( |
149 | 'interval' => 60, |
150 | 'attempts' => 2, |
151 | ), |
152 | ); |
153 | $settings['bh_wc_checkout_rate_limiter_allowed_attempts_per_interval_2'] = array( |
154 | 'title' => '', |
155 | 'id' => 'bh_wc_checkout_rate_limiter_allowed_attempts_per_interval_2', |
156 | 'type' => 'attempts_per_interval', |
157 | 'default' => array( |
158 | 'interval' => 120, |
159 | 'attempts' => 3, |
160 | ), |
161 | ); |
162 | $settings['bh_wc_checkout_rate_limiter_allowed_attempts_per_interval_3'] = array( |
163 | 'title' => '', |
164 | 'id' => 'bh_wc_checkout_rate_limiter_allowed_attempts_per_interval_3', |
165 | 'type' => 'attempts_per_interval', |
166 | 'default' => array( |
167 | 'interval' => 300, |
168 | 'attempts' => 5, |
169 | ), |
170 | ); |
171 | |
172 | $log_levels = array( 'none', LogLevel::ERROR, LogLevel::WARNING, LogLevel::NOTICE, LogLevel::INFO, LogLevel::DEBUG ); |
173 | $log_levels_option = array(); |
174 | foreach ( $log_levels as $log_level ) { |
175 | $log_levels_option[ $log_level ] = ucfirst( $log_level ); |
176 | } |
177 | |
178 | $settings['bh_wc_checkout_rate_limiter_log_level'] = array( |
179 | 'title' => __( 'Log Level', 'bh-wc-checkout-rate-limiter' ), |
180 | 'label' => __( 'Enable Logging', 'bh-wc-checkout-rate-limiter' ), |
181 | 'type' => 'select', |
182 | 'options' => $log_levels_option, |
183 | 'desc' => __( 'Increasingly detailed levels of logs. ', 'bh-wc-checkout-rate-limiter' ) . '<a href="' . admin_url( 'admin.php?page=bh-wc-checkout-rate-limiter-logs' ) . '">View Logs</a>', |
184 | 'desc_tip' => false, |
185 | 'default' => 'notice', |
186 | 'id' => 'bh_wc_checkout_rate_limiter_log_level', |
187 | ); |
188 | |
189 | $settings[] = array( |
190 | 'type' => 'sectionend', |
191 | 'id' => 'checkout-rate-limiting', |
192 | ); |
193 | |
194 | return $settings; |
195 | } |
196 | |
197 | /** |
198 | * |
199 | * // TODO: Is there a better name than $value here? (since it's an array with a "value" element). |
200 | * |
201 | * @see \WC_Admin_Settings::output_fields() |
202 | * |
203 | * @hooked woocommerce_admin_field_attempts_per_interval |
204 | * @param array<string, mixed> $value The template data to output. |
205 | */ |
206 | public function print_attempts_per_interval_settings_field( array $value ): void { |
207 | |
208 | $option_value = $value['value']; |
209 | |
210 | if ( ! isset( $option_value['attempts'] ) ) { |
211 | $option_value['attempts'] = ''; |
212 | } |
213 | |
214 | if ( ! isset( $option_value['interval'] ) ) { |
215 | $option_value['interval'] = ''; |
216 | } |
217 | |
218 | // Description handling... copied from WooCommerce WC_Admin_Settings. |
219 | $field_description = WC_Admin_Settings::get_field_description( $value ); |
220 | $description = $field_description['description']; |
221 | $tooltip_html = $field_description['tooltip_html']; |
222 | |
223 | ?> |
224 | <tr valign="top"> |
225 | <th scope="row" class="titledesc"> |
226 | <label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?> <?php |
227 | // Already escaped in WC_Admin_Settings::get_field_description(). |
228 | // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped |
229 | echo $tooltip_html; |
230 | ?> |
231 | </label> |
232 | </th> |
233 | <td class="forminp"> |
234 | <input |
235 | name="<?php echo esc_attr( $value['id'] ); ?>[attempts]" |
236 | id="<?php echo esc_attr( $value['id'] ); ?>" |
237 | type="number" |
238 | style="width: 80px;" |
239 | value="<?php echo esc_attr( $option_value['attempts'] ); ?>" |
240 | class="<?php echo esc_attr( $value['class'] ); ?>" |
241 | step="1" |
242 | min="1" |
243 | /> attempts per |
244 | <input |
245 | name="<?php echo esc_attr( $value['id'] ); ?>[interval]" |
246 | id="<?php echo esc_attr( $value['id'] ); ?>" |
247 | type="number" |
248 | style="width: 80px;" |
249 | value="<?php echo esc_attr( $option_value['interval'] ); ?>" |
250 | class="<?php echo esc_attr( $value['class'] ); ?>" |
251 | step="1" |
252 | min="0" |
253 | /> seconds. |
254 | </td> |
255 | </tr> |
256 | <?php |
257 | } |
258 | } |