diff --git a/CHANGELOG.md b/CHANGELOG.md index bef2378..fd7691e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,21 +46,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Pricing API: - `POST /wp-bnb/v1/pricing/calculate` - Full price calculation with services - `GET /wp-bnb/v1/pricing/seasons` - Get configured seasons and pricing modifiers -- API Settings tab in plugin settings: - - Enable/disable REST API toggle - - Enable/disable rate limiting toggle - - Endpoint documentation table - - Authentication instructions +- API Settings tab in plugin settings with three subtabs: + - General subtab: Enable/disable REST API, rate limiting toggle, API information + - Rate Limits subtab: Configurable time window and endpoint-specific limits + - Endpoints subtab: Full endpoint documentation with HTTP method badges +- Configurable rate limiting: + - Time window setting (10-300 seconds, default 60) + - Per-endpoint-type limits (public, availability, booking, admin) + - Settings stored in WordPress options, defaults maintained in code ### Changed - Plugin.php updated to initialize REST API on `rest_api_init` hook - Settings page now has seven tabs: General, Pricing, License, Updates, Metrics, API - README.md updated with comprehensive REST API documentation +- RateLimiter class now loads limits from WordPress options with fallback defaults ### Security -- Rate limiting: public (60/min), availability (30/min), booking (10/min), admin (120/min) +- Rate limiting: configurable per endpoint type (defaults: public 60/min, availability 30/min, booking 10/min, admin 120/min) - Admin endpoints require `edit_posts` capability - Supports WordPress Application Passwords for external API access - Client identification by user ID (authenticated) or IP address (anonymous) diff --git a/README.md b/README.md index e7d774f..9f3595a 100644 --- a/README.md +++ b/README.md @@ -451,8 +451,10 @@ The plugin provides a comprehensive REST API for integration with external appli ### Enabling the API 1. Navigate to **WP BnB → Settings → API** -2. Enable "Enable REST API" +2. In the **General** subtab, enable "Enable REST API" 3. Optionally enable rate limiting for protection against abuse +4. Configure rate limits in the **Rate Limits** subtab +5. View all available endpoints in the **Endpoints** subtab ### Base URL @@ -517,15 +519,23 @@ curl -u "username:app-password" https://site.com/wp-json/wp-bnb/v1/bookings ### Rate Limiting -When enabled, rate limits are applied per client (by user ID or IP address): +When enabled, rate limits are applied per client (by user ID or IP address). Configure limits in **Settings → API → Rate Limits**. -| Type | Limit | Applies To | -| ---- | ----- | ---------- | +**Default Limits:** + +| Type | Default | Applies To | +| ---- | ------- | ---------- | | Public | 60/min | Room/building listings | | Availability | 30/min | Availability and calendar endpoints | | Booking | 10/min | Booking creation | | Admin | 120/min | All admin endpoints | +**Configuration Options:** + +- **Time Window**: 10-300 seconds (default: 60 seconds) +- **Per-endpoint limits**: Customize for each endpoint type +- **Rate limiting toggle**: Enable/disable without losing settings + Rate limit headers are included in responses: - `X-RateLimit-Limit`: Maximum requests allowed diff --git a/assets/css/admin.css b/assets/css/admin.css index 4e03ff8..49c9829 100644 --- a/assets/css/admin.css +++ b/assets/css/admin.css @@ -491,6 +491,37 @@ height: 16px; } +/* API Method Badges */ +.wp-bnb-method { + display: inline-block; + padding: 2px 8px; + border-radius: 3px; + font-size: 11px; + font-weight: 600; + text-transform: uppercase; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; +} + +.wp-bnb-method.get { + background: #e7f5e7; + color: #1e7e1e; +} + +.wp-bnb-method.post { + background: #e7f0f5; + color: #1e5f7e; +} + +.wp-bnb-method.patch { + background: #f5f0e7; + color: #7e5f1e; +} + +.wp-bnb-method.delete { + background: #f5e7e7; + color: #7e1e1e; +} + /* Form Tables */ .form-table th { width: 200px; diff --git a/src/Api/RateLimiter.php b/src/Api/RateLimiter.php index 383750d..6588e83 100644 --- a/src/Api/RateLimiter.php +++ b/src/Api/RateLimiter.php @@ -22,23 +22,61 @@ final class RateLimiter { private const TRANSIENT_PREFIX = 'wp_bnb_rate_'; /** - * Rate limits per minute by endpoint type. + * Default rate limits per minute by endpoint type. * * @var array */ - private array $limits = array( + private const DEFAULT_LIMITS = array( 'public' => 60, // Public read endpoints. 'availability' => 30, // Availability checks. 'booking' => 10, // Booking creation. 'admin' => 120, // Admin endpoints. ); + /** + * Rate limits per minute by endpoint type. + * + * @var array + */ + private array $limits; + /** * Time window in seconds. * * @var int */ - private int $window = 60; + private int $window; + + /** + * Constructor. + */ + public function __construct() { + $this->load_limits_from_options(); + } + + /** + * Load rate limits from WordPress options. + * + * @return void + */ + private function load_limits_from_options(): void { + $this->limits = array( + 'public' => (int) get_option( 'wp_bnb_rate_limit_public', self::DEFAULT_LIMITS['public'] ), + 'availability' => (int) get_option( 'wp_bnb_rate_limit_availability', self::DEFAULT_LIMITS['availability'] ), + 'booking' => (int) get_option( 'wp_bnb_rate_limit_booking', self::DEFAULT_LIMITS['booking'] ), + 'admin' => (int) get_option( 'wp_bnb_rate_limit_admin', self::DEFAULT_LIMITS['admin'] ), + ); + $this->window = (int) get_option( 'wp_bnb_rate_limit_window', 60 ); + } + + /** + * Get default rate limits. + * + * @return array + */ + public static function get_default_limits(): array { + return self::DEFAULT_LIMITS; + } /** * Check if request is within rate limit. diff --git a/src/Plugin.php b/src/Plugin.php index e81b8a6..f9c4c60 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -1460,147 +1460,319 @@ final class Plugin { * @return void */ private function render_api_settings(): void { - $api_enabled = get_option( 'wp_bnb_api_enabled', 'yes' ); - $rate_limiting = get_option( 'wp_bnb_api_rate_limiting', 'yes' ); - $api_base_url = rest_url( RestApi::NAMESPACE ); + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Subtab switching only. + $active_subtab = isset( $_GET['subtab'] ) ? sanitize_key( $_GET['subtab'] ) : 'general'; + + $api_enabled = get_option( 'wp_bnb_api_enabled', 'yes' ); + $rate_limiting = get_option( 'wp_bnb_api_rate_limiting', 'yes' ); + $api_base_url = rest_url( RestApi::NAMESPACE ); + + // Rate limit values. + $defaults = \Magdev\WpBnb\Api\RateLimiter::get_default_limits(); + $limit_public = get_option( 'wp_bnb_rate_limit_public', $defaults['public'] ); + $limit_avail = get_option( 'wp_bnb_rate_limit_availability', $defaults['availability'] ); + $limit_booking = get_option( 'wp_bnb_rate_limit_booking', $defaults['booking'] ); + $limit_admin = get_option( 'wp_bnb_rate_limit_admin', $defaults['admin'] ); + $limit_window = get_option( 'wp_bnb_rate_limit_window', 60 ); + + $base_url = admin_url( 'admin.php?page=wp-bnb-settings&tab=api' ); ?> + + + +
-

+ + +

- - - - - - - - - -
- -

- -

-
- -

- -

-
- -

- - - - - - - - - - - - - - -
- -

- -

-
- -
- -

- -

-
- -

- -

- - +
- - - + + - - - - - - - - - - - - - - -
+ +

+ +

+
GET/buildings
GET/buildings/{id}
GET/buildings/{id}/rooms
GET/rooms
GET/rooms/{id}
GET/rooms/{id}/availability
GET/rooms/{id}/calendar
POST/availability/search
GET/services
POST/pricing/calculate
POST/bookings
- -

- - - - - + + - - - - - - - - - - - - - -
+ +

+ + + + +

+
GET/bookings
GET/bookings/{id}
PATCH/bookings/{id}
DELETE/bookings/{id}
POST/bookings/{id}/confirm
POST/bookings/{id}/check-in
POST/bookings/{id}/check-out
GET/guests
GET/guests/{id}
GET/guests/search
+ -

-

-
    -
  • Your Profile. Use Basic Auth with username and app password.', 'wp-bnb' ); ?>
  • -
  • -
+

-

- - +
- - - + + - - - - - - - -
+ +

+ +

+
60/min
30/min
10/min
120/min
+ + + + + + + + + + +

+ +

+ + + -

- -

+ + + + +

+ + +
+

+ + +

+
+ + +

+ + + + + + + + + + + + + + + + + + + + + + +
+ + +

+ +

+
+ + +

+ +

+
+ + +

+ +

+
+ + +

+ +

+
+ + +

+ +

+
+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +

+ +

+

+ + + + + + + + + + + + + + + + + + + + + +
GET/buildings
GET/buildings/{id}
GET/buildings/{id}/rooms
GET/rooms
GET/rooms/{id}
GET/rooms/{id}/availability
GET/rooms/{id}/calendar
POST/availability/search
GET/services
POST/pricing/calculate
POST/bookings
+ +

+

+ + + + + + + + + + + + + + + + + + + + +
GET/bookings
GET/bookings/{id}
PATCH/bookings/{id}
DELETE/bookings/{id}
POST/bookings/{id}/confirm
POST/bookings/{id}/check-in
POST/bookings/{id}/check-out
GET/guests
GET/guests/{id}
GET/guests/search
+ +

+

+ + + + + + + + + + +
+ + + +

Your Profile.', 'wp-bnb' ); ?>

+

Authorization: Basic base64(username:app-password)

+

+
+ + + +

+

X-WP-Nonce:

+

+
+