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 | } |