[1.3.0] — 2025-06-12 — OTP Rate Limiting & Square Refunds
Added
OTP Rate Limiting (class-otp.php)
- Per-contact limit: max 3 OTP sends per contact per hour — prevents a single email/phone from being hammered
- Per-IP limit: max 10 OTP sends per IP per hour — prevents bot enumeration from one network
- Both limits use WP transients with a sliding 1-hour window
- On limit hit: returns a
WP_Errorwith a human-readable retry time ("Please wait 47 minutes…") - HTTP 429 status code returned to the browser on rate limit errors
- Client IP resolved via
HTTP_CF_CONNECTING_IP→HTTP_X_FORWARDED_FOR→HTTP_X_REAL_IP→REMOTE_ADDR— correct behind Cloudflare and common reverse proxies CatCafe_OTP::remaining_sends()— public helper returning remaining sends for a contact this hour (available for UI use)- Existing verify attempt-lockout (5 max, then code invalidated) unchanged
Square Refund API (class-square.php)
CatCafe_Square::refund_reservation( $post_id, $reason, $amount )— calls Square Refunds API using the_catcafe_square_payment_idstored on the reservation- Full or partial refund: pass
nullfor amount to refund the full reservation total; pass a dollar amount for partial - Idempotency key per refund call prevents duplicate refunds on retry
- Pins Square API version to
2024-01-18for stability - Auto-detects sandbox vs production based on token format and
WP_DEBUG - On success: stores
_catcafe_square_refund_id,_catcafe_amount_refunded,_catcafe_refund_reason,_catcafe_refund_initiated_aton the reservation; then cancels the reservation and notifies the guest CatCafe_Square::get_refund_status( $post_id )— polls Square for current refund status (useful for pending refunds)- Clear error if Access Token not configured, payment ID missing, amount invalid, or already cancelled
Admin — Cancel & Refund button
- "↩ Cancel & Refund" button (purple) shown on confirmed reservations that have a Square payment ID and no existing refund
- Plain "✕ Cancel" shown for unconfirmed or non-payment reservations
- Clicking prompts for: reason (pre-filled "Cancelled by café staff"), refund amount (pre-filled with full total), final confirmation
- On success: toast with refund ID shown, page reloads with updated status
- On failure (Square error, misconfigured token, etc.): error shown inline, button re-enabled
- Refund confirmation shown inline in table ("✓ Refunded $XX.XX") for already-refunded rows
REST API
POST /wp-json/catcafe/v1/admin/reservations/{id}/refund— admin-only; acceptsreasonandamountparams
Changed
- Plugin version bumped to
1.3.0 CATCAFE_VERSIONconstant updated
Full Changelog: https://github.com/LouGriffith/catcafe-booking/commits/1.3.0