2026-01-31 13:15:13 +01:00
< ? php
/**
* Main Plugin class .
*
* @ package Magdev\WpBnb
*/
declare ( strict_types = 1 );
namespace Magdev\WpBnb ;
2026-01-31 14:37:48 +01:00
use Magdev\WpBnb\Admin\Calendar as CalendarAdmin ;
2026-02-03 20:20:27 +01:00
use Magdev\WpBnb\Admin\Dashboard as DashboardAdmin ;
use Magdev\WpBnb\Admin\Reports as ReportsAdmin ;
2026-01-31 14:10:30 +01:00
use Magdev\WpBnb\Admin\Seasons as SeasonsAdmin ;
Add frontend features with search, shortcodes, widgets, and blocks (v0.6.0)
- Room search with availability, capacity, room type, amenity, price range, and building filters
- AJAX-powered search with pagination and load more
- Shortcodes: [bnb_buildings], [bnb_rooms], [bnb_room_search], [bnb_building], [bnb_room]
- Widgets: Similar Rooms, Building Rooms, Availability Calendar
- Gutenberg blocks: Building, Room, Room Search, Buildings List, Rooms List
- Frontend CSS with responsive design and CSS custom properties
- Frontend JavaScript with SearchForm, CalendarWidget, AvailabilityForm, PriceCalculator
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 14:08:11 +01:00
use Magdev\WpBnb\Blocks\BlockRegistrar ;
2026-01-31 14:37:48 +01:00
use Magdev\WpBnb\Booking\Availability ;
use Magdev\WpBnb\Booking\EmailNotifier ;
Add frontend features with search, shortcodes, widgets, and blocks (v0.6.0)
- Room search with availability, capacity, room type, amenity, price range, and building filters
- AJAX-powered search with pagination and load more
- Shortcodes: [bnb_buildings], [bnb_rooms], [bnb_room_search], [bnb_building], [bnb_room]
- Widgets: Similar Rooms, Building Rooms, Availability Calendar
- Gutenberg blocks: Building, Room, Room Search, Buildings List, Rooms List
- Frontend CSS with responsive design and CSS custom properties
- Frontend JavaScript with SearchForm, CalendarWidget, AvailabilityForm, PriceCalculator
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 14:08:11 +01:00
use Magdev\WpBnb\Frontend\Search ;
use Magdev\WpBnb\Frontend\Shortcodes ;
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
use Magdev\WpBnb\Api\RestApi ;
2026-02-03 16:30:30 +01:00
use Magdev\WpBnb\Integration\CF7 ;
2026-02-03 20:40:54 +01:00
use Magdev\WpBnb\Integration\Prometheus ;
Add WooCommerce integration for payments, invoices, and order management (v0.11.0)
- Product sync: Virtual WC products for rooms with bidirectional linking
- Cart/Checkout: Booking data in cart items, availability validation, dynamic pricing
- Orders: Automatic booking creation on payment, status mapping, guest record creation
- Invoices: PDF generation via mPDF, auto-attach to emails, configurable numbering
- Refunds: Full refund cancels booking, partial refund records amount only
- Admin: Cross-linked columns and row actions between bookings and orders
- Settings: WooCommerce tab with subtabs (General, Products, Orders, Invoices)
- HPOS compatibility declared for High-Performance Order Storage
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 22:40:36 +01:00
use Magdev\WpBnb\Integration\WooCommerce\Manager as WooCommerceManager ;
Add frontend features with search, shortcodes, widgets, and blocks (v0.6.0)
- Room search with availability, capacity, room type, amenity, price range, and building filters
- AJAX-powered search with pagination and load more
- Shortcodes: [bnb_buildings], [bnb_rooms], [bnb_room_search], [bnb_building], [bnb_room]
- Widgets: Similar Rooms, Building Rooms, Availability Calendar
- Gutenberg blocks: Building, Room, Room Search, Buildings List, Rooms List
- Frontend CSS with responsive design and CSS custom properties
- Frontend JavaScript with SearchForm, CalendarWidget, AvailabilityForm, PriceCalculator
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 14:08:11 +01:00
use Magdev\WpBnb\Frontend\Widgets\AvailabilityCalendar ;
use Magdev\WpBnb\Frontend\Widgets\BuildingRooms ;
use Magdev\WpBnb\Frontend\Widgets\SimilarRooms ;
2026-01-31 13:15:13 +01:00
use Magdev\WpBnb\License\Manager as LicenseManager ;
2026-02-03 15:18:27 +01:00
use Magdev\WpBnb\License\Updater as LicenseUpdater ;
use Magdev\WcLicensedProductClient\Dto\UpdateInfo ;
2026-01-31 14:37:48 +01:00
use Magdev\WpBnb\PostTypes\Booking ;
2026-01-31 13:45:06 +01:00
use Magdev\WpBnb\PostTypes\Building ;
2026-01-31 14:59:43 +01:00
use Magdev\WpBnb\PostTypes\Guest ;
2026-01-31 13:45:06 +01:00
use Magdev\WpBnb\PostTypes\Room ;
2026-01-31 15:19:56 +01:00
use Magdev\WpBnb\PostTypes\Service ;
Add frontend features with search, shortcodes, widgets, and blocks (v0.6.0)
- Room search with availability, capacity, room type, amenity, price range, and building filters
- AJAX-powered search with pagination and load more
- Shortcodes: [bnb_buildings], [bnb_rooms], [bnb_room_search], [bnb_building], [bnb_room]
- Widgets: Similar Rooms, Building Rooms, Availability Calendar
- Gutenberg blocks: Building, Room, Room Search, Buildings List, Rooms List
- Frontend CSS with responsive design and CSS custom properties
- Frontend JavaScript with SearchForm, CalendarWidget, AvailabilityForm, PriceCalculator
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 14:08:11 +01:00
use Magdev\WpBnb\Pricing\Calculator ;
2026-01-31 14:59:43 +01:00
use Magdev\WpBnb\Privacy\Manager as PrivacyManager ;
2026-01-31 14:10:30 +01:00
use Magdev\WpBnb\Pricing\Season ;
2026-01-31 13:45:06 +01:00
use Magdev\WpBnb\Taxonomies\Amenity ;
use Magdev\WpBnb\Taxonomies\RoomType ;
2026-01-31 15:19:56 +01:00
use Magdev\WpBnb\Taxonomies\ServiceCategory ;
2026-01-31 13:15:13 +01:00
use Twig\Environment ;
use Twig\Loader\FilesystemLoader ;
/**
* Main Plugin singleton class .
*/
final class Plugin {
/**
* Plugin instance .
*
* @ var Plugin | null
*/
private static ? Plugin $instance = null ;
/**
* Twig environment .
*
* @ var Environment | null
*/
private ? Environment $twig = null ;
/**
* Get plugin instance .
*
* @ return Plugin
*/
public static function get_instance () : Plugin {
if ( null === self :: $instance ) {
self :: $instance = new self ();
}
return self :: $instance ;
}
/**
* Private constructor to enforce singleton .
*/
private function __construct () {
$this -> init_hooks ();
$this -> init_components ();
}
/**
* Initialize WordPress hooks .
*
* @ return void
*/
private function init_hooks () : void {
// Load text domain.
add_action ( 'init' , array ( $this , 'load_textdomain' ) );
// Register assets.
add_action ( 'admin_enqueue_scripts' , array ( $this , 'enqueue_admin_assets' ) );
add_action ( 'wp_enqueue_scripts' , array ( $this , 'enqueue_frontend_assets' ) );
// Add plugin action links.
add_filter ( 'plugin_action_links_' . WP_BNB_BASENAME , array ( $this , 'add_action_links' ) );
2026-01-31 13:45:06 +01:00
// Register custom post types and taxonomies.
$this -> register_post_types ();
$this -> register_taxonomies ();
}
/**
* Register custom post types .
*
* @ return void
*/
private function register_post_types () : void {
Building :: init ();
Room :: init ();
2026-01-31 14:37:48 +01:00
Booking :: init ();
2026-01-31 14:59:43 +01:00
Guest :: init ();
2026-01-31 15:19:56 +01:00
Service :: init ();
2026-01-31 13:45:06 +01:00
}
/**
* Register custom taxonomies .
*
* @ return void
*/
private function register_taxonomies () : void {
// Taxonomies must be registered before post types that use them.
Amenity :: init ();
RoomType :: init ();
2026-01-31 15:19:56 +01:00
ServiceCategory :: init ();
2026-01-31 13:15:13 +01:00
}
/**
* Initialize plugin components .
*
* @ return void
*/
private function init_components () : void {
// Initialize License Manager (always active for admin).
LicenseManager :: get_instance ();
2026-02-03 15:18:27 +01:00
// Initialize auto-updater (requires license configuration).
$this -> init_updater ();
2026-02-03 17:18:46 +01:00
// Initialize Contact Form 7 integration if CF7 is active.
// This runs in both admin (for tag generators) and frontend (for form rendering).
if ( class_exists ( 'WPCF7' ) ) {
CF7 :: init ();
}
2026-02-03 20:40:54 +01:00
// Initialize Prometheus metrics integration.
Prometheus :: init ();
Add WooCommerce integration for payments, invoices, and order management (v0.11.0)
- Product sync: Virtual WC products for rooms with bidirectional linking
- Cart/Checkout: Booking data in cart items, availability validation, dynamic pricing
- Orders: Automatic booking creation on payment, status mapping, guest record creation
- Invoices: PDF generation via mPDF, auto-attach to emails, configurable numbering
- Refunds: Full refund cancels booking, partial refund records amount only
- Admin: Cross-linked columns and row actions between bookings and orders
- Settings: WooCommerce tab with subtabs (General, Products, Orders, Invoices)
- HPOS compatibility declared for High-Performance Order Storage
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 22:40:36 +01:00
// Initialize WooCommerce integration if WooCommerce is active.
if ( class_exists ( 'WooCommerce' ) ) {
WooCommerceManager :: init ();
}
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
// Initialize REST API.
$this -> init_rest_api ();
2026-01-31 13:15:13 +01:00
// Initialize admin components.
if ( is_admin () ) {
$this -> init_admin ();
}
// Initialize frontend components only if licensed.
if ( ! is_admin () && LicenseManager :: is_license_valid () ) {
$this -> init_frontend ();
}
}
2026-02-03 15:18:27 +01:00
/**
* Initialize the plugin auto - updater .
*
* @ return void
*/
private function init_updater () : void {
$updater = new LicenseUpdater (
plugin_file : WP_BNB_PATH . 'wp-bnb.php' ,
current_version : WP_BNB_VERSION ,
);
$updater -> init ();
}
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
/**
* Initialize the REST API .
*
* @ return void
*/
private function init_rest_api () : void {
$api = new RestApi ();
$api -> init ();
}
2026-01-31 13:15:13 +01:00
/**
* Initialize admin components .
*
* @ return void
*/
private function init_admin () : void {
// Admin menu and settings will be added here.
add_action ( 'admin_menu' , array ( $this , 'register_admin_menu' ) );
2026-02-03 15:18:27 +01:00
add_action ( 'admin_menu' , array ( $this , 'reorder_admin_menu' ), 99 );
2026-01-31 13:15:13 +01:00
add_action ( 'admin_init' , array ( $this , 'register_settings' ) );
2026-01-31 14:10:30 +01:00
// Initialize seasons admin page.
SeasonsAdmin :: init ();
2026-01-31 14:37:48 +01:00
// Initialize calendar admin page.
CalendarAdmin :: init ();
// Initialize email notifier.
EmailNotifier :: init ();
2026-01-31 14:59:43 +01:00
// Initialize privacy manager for GDPR compliance.
PrivacyManager :: init ();
2026-01-31 14:37:48 +01:00
// Register AJAX handlers.
add_action ( 'wp_ajax_wp_bnb_check_availability' , array ( $this , 'ajax_check_availability' ) );
2026-01-31 14:59:43 +01:00
add_action ( 'wp_ajax_wp_bnb_search_guest' , array ( $this , 'ajax_search_guest' ) );
2026-01-31 13:15:13 +01:00
}
/**
* Initialize frontend components .
*
* @ return void
*/
private function init_frontend () : void {
Add frontend features with search, shortcodes, widgets, and blocks (v0.6.0)
- Room search with availability, capacity, room type, amenity, price range, and building filters
- AJAX-powered search with pagination and load more
- Shortcodes: [bnb_buildings], [bnb_rooms], [bnb_room_search], [bnb_building], [bnb_room]
- Widgets: Similar Rooms, Building Rooms, Availability Calendar
- Gutenberg blocks: Building, Room, Room Search, Buildings List, Rooms List
- Frontend CSS with responsive design and CSS custom properties
- Frontend JavaScript with SearchForm, CalendarWidget, AvailabilityForm, PriceCalculator
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 14:08:11 +01:00
// Initialize search (registers AJAX handlers).
Search :: init ();
// Initialize shortcodes.
Shortcodes :: init ();
// Initialize Gutenberg blocks.
BlockRegistrar :: init ();
// Register widgets.
add_action ( 'widgets_init' , array ( $this , 'register_widgets' ) );
}
/**
* Register frontend widgets .
*
* @ return void
*/
public function register_widgets () : void {
register_widget ( SimilarRooms :: class );
register_widget ( BuildingRooms :: class );
register_widget ( AvailabilityCalendar :: class );
2026-01-31 13:15:13 +01:00
}
/**
* Load plugin text domain .
*
* @ return void
*/
public function load_textdomain () : void {
load_plugin_textdomain (
'wp-bnb' ,
false ,
dirname ( WP_BNB_BASENAME ) . '/languages'
);
}
/**
* Enqueue admin assets .
*
* @ param string $hook_suffix Current admin page hook .
* @ return void
*/
public function enqueue_admin_assets ( string $hook_suffix ) : void {
2026-01-31 13:45:06 +01:00
global $post_type ;
// Check if we're on plugin pages or editing our custom post types.
2026-01-31 14:10:30 +01:00
$is_plugin_page = strpos ( $hook_suffix , 'wp-bnb' ) !== false ;
2026-01-31 15:19:56 +01:00
$is_our_post_type = in_array ( $post_type , array ( Building :: POST_TYPE , Room :: POST_TYPE , Booking :: POST_TYPE , Guest :: POST_TYPE , Service :: POST_TYPE ), true );
2026-01-31 14:10:30 +01:00
$is_edit_screen = in_array ( $hook_suffix , array ( 'post.php' , 'post-new.php' ), true );
2026-02-03 20:20:27 +01:00
$is_dashboard = 'toplevel_page_wp-bnb' === $hook_suffix ;
2026-01-31 13:45:06 +01:00
if ( ! $is_plugin_page && ! ( $is_our_post_type && $is_edit_screen ) ) {
2026-01-31 13:15:13 +01:00
return ;
}
wp_enqueue_style (
'wp-bnb-admin' ,
WP_BNB_URL . 'assets/css/admin.css' ,
array (),
WP_BNB_VERSION
);
2026-01-31 13:45:06 +01:00
$script_deps = array ( 'jquery' );
// Add media dependencies for room gallery.
if ( Room :: POST_TYPE === $post_type && $is_edit_screen ) {
wp_enqueue_media ();
$script_deps [] = 'jquery-ui-sortable' ;
}
2026-02-03 20:20:27 +01:00
// Add Chart.js for dashboard.
if ( $is_dashboard ) {
wp_enqueue_script (
'chartjs' ,
'https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js' ,
array (),
'4.4.1' ,
true
);
$script_deps [] = 'chartjs' ;
}
2026-01-31 13:15:13 +01:00
wp_enqueue_script (
'wp-bnb-admin' ,
WP_BNB_URL . 'assets/js/admin.js' ,
2026-01-31 13:45:06 +01:00
$script_deps ,
2026-01-31 13:15:13 +01:00
WP_BNB_VERSION ,
true
);
2026-02-03 20:20:27 +01:00
// Build localize data.
$localize_data = array (
'ajaxUrl' => admin_url ( 'admin-ajax.php' ),
'nonce' => wp_create_nonce ( 'wp_bnb_admin_nonce' ),
'postType' => $post_type ,
'isDashboard' => $is_dashboard ,
'i18n' => array (
'validating' => __ ( 'Validating...' , 'wp-bnb' ),
'activating' => __ ( 'Activating...' , 'wp-bnb' ),
'error' => __ ( 'An error occurred. Please try again.' , 'wp-bnb' ),
'selectImages' => __ ( 'Select Images' , 'wp-bnb' ),
'addToGallery' => __ ( 'Add to Gallery' , 'wp-bnb' ),
'confirmRemove' => __ ( 'Are you sure you want to remove this image?' , 'wp-bnb' ),
'increase' => __ ( 'increase' , 'wp-bnb' ),
'discount' => __ ( 'discount' , 'wp-bnb' ),
'normalPrice' => __ ( 'Normal price' , 'wp-bnb' ),
'checking' => __ ( 'Checking availability...' , 'wp-bnb' ),
'available' => __ ( 'Available' , 'wp-bnb' ),
'notAvailable' => __ ( 'Not available - conflicts with existing booking' , 'wp-bnb' ),
'selectRoomAndDates' => __ ( 'Select room and dates to check availability' , 'wp-bnb' ),
'nights' => __ ( 'nights' , 'wp-bnb' ),
'night' => __ ( 'night' , 'wp-bnb' ),
'calculating' => __ ( 'Calculating price...' , 'wp-bnb' ),
'searchingGuests' => __ ( 'Searching...' , 'wp-bnb' ),
'noGuestsFound' => __ ( 'No guests found' , 'wp-bnb' ),
'selectGuest' => __ ( 'Select' , 'wp-bnb' ),
'guestBlocked' => __ ( 'Blocked' , 'wp-bnb' ),
'perNightDescription' => __ ( 'This price will be charged per night of the stay.' , 'wp-bnb' ),
'perBookingDescription' => __ ( 'This price will be charged once for the booking.' , 'wp-bnb' ),
'justNow' => __ ( 'Just now' , 'wp-bnb' ),
'updateAvailable' => __ ( 'Update available!' , 'wp-bnb' ),
'upToDate' => __ ( '(You are up to date)' , 'wp-bnb' ),
'checkingUpdates' => __ ( 'Checking for updates...' , 'wp-bnb' ),
'occupancy' => __ ( 'Occupancy %' , 'wp-bnb' ),
'revenue' => __ ( 'Revenue' , 'wp-bnb' ),
),
2026-01-31 13:15:13 +01:00
);
2026-02-03 20:20:27 +01:00
// Add chart data for dashboard.
if ( $is_dashboard ) {
$localize_data [ 'chartData' ] = array (
'occupancy' => DashboardAdmin :: get_occupancy_trend_data ( 30 ),
'revenue' => DashboardAdmin :: get_revenue_trend_data ( 6 ),
);
}
wp_localize_script ( 'wp-bnb-admin' , 'wpBnbAdmin' , $localize_data );
2026-01-31 13:15:13 +01:00
}
/**
* Enqueue frontend assets .
*
* @ return void
*/
public function enqueue_frontend_assets () : void {
// Only load if licensed.
if ( ! LicenseManager :: is_license_valid () ) {
return ;
}
wp_enqueue_style (
'wp-bnb-frontend' ,
WP_BNB_URL . 'assets/css/frontend.css' ,
array (),
WP_BNB_VERSION
);
wp_enqueue_script (
'wp-bnb-frontend' ,
WP_BNB_URL . 'assets/js/frontend.js' ,
array (),
WP_BNB_VERSION ,
true
);
Add frontend features with search, shortcodes, widgets, and blocks (v0.6.0)
- Room search with availability, capacity, room type, amenity, price range, and building filters
- AJAX-powered search with pagination and load more
- Shortcodes: [bnb_buildings], [bnb_rooms], [bnb_room_search], [bnb_building], [bnb_room]
- Widgets: Similar Rooms, Building Rooms, Availability Calendar
- Gutenberg blocks: Building, Room, Room Search, Buildings List, Rooms List
- Frontend CSS with responsive design and CSS custom properties
- Frontend JavaScript with SearchForm, CalendarWidget, AvailabilityForm, PriceCalculator
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 14:08:11 +01:00
wp_localize_script (
'wp-bnb-frontend' ,
'wpBnbFrontend' ,
array (
'ajaxUrl' => admin_url ( 'admin-ajax.php' ),
'nonce' => wp_create_nonce ( 'wp_bnb_frontend_nonce' ),
'i18n' => array (
'searching' => __ ( 'Searching...' , 'wp-bnb' ),
'noResults' => __ ( 'No rooms found matching your criteria.' , 'wp-bnb' ),
'resultsFound' => __ ( '%d rooms found' , 'wp-bnb' ),
'loadMore' => __ ( 'Load More' , 'wp-bnb' ),
'viewDetails' => __ ( 'View Details' , 'wp-bnb' ),
'perNight' => __ ( 'night' , 'wp-bnb' ),
'guests' => __ ( 'guests' , 'wp-bnb' ),
'invalidDateRange' => __ ( 'Check-out must be after check-in' , 'wp-bnb' ),
'selectDates' => __ ( 'Please select check-in and check-out dates.' , 'wp-bnb' ),
'available' => __ ( 'Room is available!' , 'wp-bnb' ),
'notAvailable' => __ ( 'Sorry, the room is not available for these dates.' , 'wp-bnb' ),
'totalPrice' => __ ( 'Total' , 'wp-bnb' ),
'bookNow' => __ ( 'Book Now' , 'wp-bnb' ),
'total' => __ ( 'Total' , 'wp-bnb' ),
'nights' => __ ( 'nights' , 'wp-bnb' ),
'basePrice' => __ ( 'Base' , 'wp-bnb' ),
'weekendSurcharge' => __ ( 'Weekend surcharge' , 'wp-bnb' ),
'season' => __ ( 'Season' , 'wp-bnb' ),
),
)
);
2026-02-03 16:30:30 +01:00
// Load CF7 integration assets if CF7 is active.
if ( class_exists ( 'WPCF7' ) ) {
wp_enqueue_style (
'wp-bnb-cf7' ,
WP_BNB_URL . 'assets/css/cf7-integration.css' ,
array ( 'contact-form-7' ),
WP_BNB_VERSION
);
wp_enqueue_script (
'wp-bnb-cf7' ,
WP_BNB_URL . 'assets/js/cf7-integration.js' ,
array ( 'contact-form-7' ),
WP_BNB_VERSION ,
true
);
wp_localize_script (
'wp-bnb-cf7' ,
'wpBnbCF7' ,
array (
'ajaxUrl' => admin_url ( 'admin-ajax.php' ),
'nonce' => wp_create_nonce ( 'wp_bnb_frontend_nonce' ),
'i18n' => array (
'selectRoom' => __ ( '-- Select Room --' , 'wp-bnb' ),
'checking' => __ ( 'Checking availability...' , 'wp-bnb' ),
'available' => __ ( 'Room is available!' , 'wp-bnb' ),
'unavailable' => __ ( 'Room is not available for these dates' , 'wp-bnb' ),
'invalidDateRange' => __ ( 'Check-out must be after check-in' , 'wp-bnb' ),
'capacityExceeded' => __ ( 'Maximum %d guests for this room' , 'wp-bnb' ),
'estimatedTotal' => __ ( 'Estimated Total' , 'wp-bnb' ),
'nights' => __ ( 'nights' , 'wp-bnb' ),
),
)
);
}
2026-01-31 13:15:13 +01:00
}
/**
* Add plugin action links .
*
* @ param array $links Existing plugin links .
* @ return array
*/
public function add_action_links ( array $links ) : array {
$plugin_links = array (
'<a href="' . esc_url ( admin_url ( 'admin.php?page=wp-bnb-settings' ) ) . '">' . esc_html__ ( 'Settings' , 'wp-bnb' ) . '</a>' ,
);
return array_merge ( $plugin_links , $links );
}
/**
* Register admin menu .
*
* @ return void
*/
public function register_admin_menu () : void {
// Main menu.
add_menu_page (
__ ( 'WP BnB' , 'wp-bnb' ),
__ ( 'WP BnB' , 'wp-bnb' ),
'manage_options' ,
'wp-bnb' ,
array ( $this , 'render_dashboard_page' ),
'dashicons-building' ,
30
);
// Dashboard submenu.
add_submenu_page (
'wp-bnb' ,
__ ( 'Dashboard' , 'wp-bnb' ),
__ ( 'Dashboard' , 'wp-bnb' ),
'manage_options' ,
'wp-bnb' ,
array ( $this , 'render_dashboard_page' )
);
2026-02-03 20:20:27 +01:00
// Reports submenu.
add_submenu_page (
'wp-bnb' ,
__ ( 'Reports' , 'wp-bnb' ),
__ ( 'Reports' , 'wp-bnb' ),
'manage_options' ,
'wp-bnb-reports' ,
array ( $this , 'render_reports_page' )
);
2026-01-31 13:15:13 +01:00
// Settings submenu.
add_submenu_page (
'wp-bnb' ,
__ ( 'Settings' , 'wp-bnb' ),
__ ( 'Settings' , 'wp-bnb' ),
'manage_options' ,
'wp-bnb-settings' ,
array ( $this , 'render_settings_page' )
);
}
2026-02-03 15:18:27 +01:00
/**
* Reorder the admin submenu items .
*
* Places Dashboard at top , Settings at bottom , and organizes
* the remaining items in logical order .
*
* @ return void
*/
public function reorder_admin_menu () : void {
global $submenu ;
if ( ! isset ( $submenu [ 'wp-bnb' ] ) ) {
return ;
}
// Define the desired order of menu slugs.
$desired_order = array (
2026-02-03 20:20:27 +01:00
'wp-bnb' , // Dashboard.
2026-02-03 15:18:27 +01:00
'edit.php?post_type=bnb_building' , // Buildings.
'edit.php?post_type=bnb_room' , // Rooms.
'edit.php?post_type=bnb_booking' , // Bookings.
'edit.php?post_type=bnb_guest' , // Guests.
'edit.php?post_type=bnb_service' , // Services.
2026-02-03 20:20:27 +01:00
'wp-bnb-calendar' , // Calendar.
'wp-bnb-reports' , // Reports.
'wp-bnb-seasons' , // Seasons.
'wp-bnb-settings' , // Settings (always last).
2026-02-03 15:18:27 +01:00
);
$current_menu = $submenu [ 'wp-bnb' ];
$ordered_menu = array ();
$index = 0 ;
// Add items in the desired order.
foreach ( $desired_order as $slug ) {
foreach ( $current_menu as $key => $item ) {
if ( $item [ 2 ] === $slug ) {
$ordered_menu [ $index ] = $item ;
unset ( $current_menu [ $key ] );
++ $index ;
break ;
}
}
}
// Append any remaining items not in the desired order.
foreach ( $current_menu as $item ) {
$ordered_menu [ $index ] = $item ;
++ $index ;
}
$submenu [ 'wp-bnb' ] = $ordered_menu ;
}
2026-01-31 13:15:13 +01:00
/**
* Register plugin settings .
*
* @ return void
*/
public function register_settings () : void {
// License settings are handled by LicenseManager.
// Additional settings will be added here.
}
/**
* Render dashboard page .
*
* @ return void
*/
public function render_dashboard_page () : void {
2026-02-03 20:20:27 +01:00
DashboardAdmin :: render ();
}
/**
* Render reports page .
*
* @ return void
*/
public function render_reports_page () : void {
ReportsAdmin :: render ();
2026-01-31 13:15:13 +01:00
}
/**
* Render settings page .
*
* @ return void
*/
public function render_settings_page () : void {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Tab switching only.
$active_tab = isset ( $_GET [ 'tab' ] ) ? sanitize_key ( $_GET [ 'tab' ] ) : 'general' ;
// Handle form submission.
if ( isset ( $_POST [ 'wp_bnb_settings_nonce' ] ) && wp_verify_nonce ( sanitize_key ( $_POST [ 'wp_bnb_settings_nonce' ] ), 'wp_bnb_save_settings' ) ) {
$this -> save_settings ( $active_tab );
}
?>
< div class = " wrap " >
< h1 >< ? php esc_html_e ( 'WP BnB Settings' , 'wp-bnb' ); ?> </h1>
< nav class = " nav-tab-wrapper " >
< a href = " <?php echo esc_url( admin_url( 'admin.php?page=wp-bnb-settings&tab=general' ) ); ?> "
class = " nav-tab <?php echo 'general' === $active_tab ? 'nav-tab-active' : ''; ?> " >
< ? php esc_html_e ( 'General' , 'wp-bnb' ); ?>
</ a >
2026-01-31 14:10:30 +01:00
< a href = " <?php echo esc_url( admin_url( 'admin.php?page=wp-bnb-settings&tab=pricing' ) ); ?> "
class = " nav-tab <?php echo 'pricing' === $active_tab ? 'nav-tab-active' : ''; ?> " >
< ? php esc_html_e ( 'Pricing' , 'wp-bnb' ); ?>
</ a >
2026-01-31 13:15:13 +01:00
< a href = " <?php echo esc_url( admin_url( 'admin.php?page=wp-bnb-settings&tab=license' ) ); ?> "
class = " nav-tab <?php echo 'license' === $active_tab ? 'nav-tab-active' : ''; ?> " >
< ? php esc_html_e ( 'License' , 'wp-bnb' ); ?>
</ a >
2026-02-03 15:18:27 +01:00
< a href = " <?php echo esc_url( admin_url( 'admin.php?page=wp-bnb-settings&tab=updates' ) ); ?> "
class = " nav-tab <?php echo 'updates' === $active_tab ? 'nav-tab-active' : ''; ?> " >
< ? php esc_html_e ( 'Updates' , 'wp-bnb' ); ?>
</ a >
2026-02-03 20:40:54 +01:00
< a href = " <?php echo esc_url( admin_url( 'admin.php?page=wp-bnb-settings&tab=metrics' ) ); ?> "
class = " nav-tab <?php echo 'metrics' === $active_tab ? 'nav-tab-active' : ''; ?> " >
< ? php esc_html_e ( 'Metrics' , 'wp-bnb' ); ?>
</ a >
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
< a href = " <?php echo esc_url( admin_url( 'admin.php?page=wp-bnb-settings&tab=api' ) ); ?> "
class = " nav-tab <?php echo 'api' === $active_tab ? 'nav-tab-active' : ''; ?> " >
< ? php esc_html_e ( 'API' , 'wp-bnb' ); ?>
</ a >
Add WooCommerce integration for payments, invoices, and order management (v0.11.0)
- Product sync: Virtual WC products for rooms with bidirectional linking
- Cart/Checkout: Booking data in cart items, availability validation, dynamic pricing
- Orders: Automatic booking creation on payment, status mapping, guest record creation
- Invoices: PDF generation via mPDF, auto-attach to emails, configurable numbering
- Refunds: Full refund cancels booking, partial refund records amount only
- Admin: Cross-linked columns and row actions between bookings and orders
- Settings: WooCommerce tab with subtabs (General, Products, Orders, Invoices)
- HPOS compatibility declared for High-Performance Order Storage
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 22:40:36 +01:00
< a href = " <?php echo esc_url( admin_url( 'admin.php?page=wp-bnb-settings&tab=woocommerce' ) ); ?> "
class = " nav-tab <?php echo 'woocommerce' === $active_tab ? 'nav-tab-active' : ''; ?> " >
< ? php esc_html_e ( 'WooCommerce' , 'wp-bnb' ); ?>
</ a >
2026-01-31 13:15:13 +01:00
</ nav >
< div class = " tab-content " >
< ? php
switch ( $active_tab ) {
2026-01-31 14:10:30 +01:00
case 'pricing' :
$this -> render_pricing_settings ();
break ;
2026-01-31 13:15:13 +01:00
case 'license' :
$this -> render_license_settings ();
break ;
2026-02-03 15:18:27 +01:00
case 'updates' :
$this -> render_updates_settings ();
break ;
2026-02-03 20:40:54 +01:00
case 'metrics' :
$this -> render_metrics_settings ();
break ;
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
case 'api' :
$this -> render_api_settings ();
break ;
Add WooCommerce integration for payments, invoices, and order management (v0.11.0)
- Product sync: Virtual WC products for rooms with bidirectional linking
- Cart/Checkout: Booking data in cart items, availability validation, dynamic pricing
- Orders: Automatic booking creation on payment, status mapping, guest record creation
- Invoices: PDF generation via mPDF, auto-attach to emails, configurable numbering
- Refunds: Full refund cancels booking, partial refund records amount only
- Admin: Cross-linked columns and row actions between bookings and orders
- Settings: WooCommerce tab with subtabs (General, Products, Orders, Invoices)
- HPOS compatibility declared for High-Performance Order Storage
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 22:40:36 +01:00
case 'woocommerce' :
$this -> render_woocommerce_settings ();
break ;
2026-01-31 13:15:13 +01:00
default :
$this -> render_general_settings ();
break ;
}
?>
</ div >
</ div >
< ? php
}
/**
* Render general settings tab .
*
* @ return void
*/
private function render_general_settings () : void {
?>
< form method = " post " action = " " >
< ? php wp_nonce_field ( 'wp_bnb_save_settings' , 'wp_bnb_settings_nonce' ); ?>
2026-02-03 15:18:27 +01:00
< h2 >< ? php esc_html_e ( 'Business Information' , 'wp-bnb' ); ?> </h2>
2026-01-31 13:15:13 +01:00
< table class = " form-table " role = " presentation " >
< tr >
< th scope = " row " >
< label for = " wp_bnb_business_name " >< ? php esc_html_e ( 'Business Name' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< input type = " text " name = " wp_bnb_business_name " id = " wp_bnb_business_name "
value = " <?php echo esc_attr( get_option( 'wp_bnb_business_name', '' ) ); ?> "
class = " regular-text " >
< p class = " description " >< ? php esc_html_e ( 'The name of your B&B business.' , 'wp-bnb' ); ?> </p>
</ td >
</ tr >
< tr >
< th scope = " row " >
< label for = " wp_bnb_currency " >< ? php esc_html_e ( 'Currency' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< select name = " wp_bnb_currency " id = " wp_bnb_currency " >
< ? php
$currencies = array (
'CHF' => __ ( 'Swiss Franc (CHF)' , 'wp-bnb' ),
'EUR' => __ ( 'Euro (EUR)' , 'wp-bnb' ),
'USD' => __ ( 'US Dollar (USD)' , 'wp-bnb' ),
'GBP' => __ ( 'British Pound (GBP)' , 'wp-bnb' ),
);
$current = get_option ( 'wp_bnb_currency' , 'CHF' );
foreach ( $currencies as $code => $label ) :
?>
< option value = " <?php echo esc_attr( $code ); ?> " < ? php selected ( $current , $code ); ?> >
< ? php echo esc_html ( $label ); ?>
</ option >
< ? php endforeach ; ?>
</ select >
</ td >
</ tr >
</ table >
2026-02-03 15:18:27 +01:00
< h2 >< ? php esc_html_e ( 'Address' , 'wp-bnb' ); ?> </h2>
< table class = " form-table " role = " presentation " >
< tr >
< th scope = " row " >
< label for = " wp_bnb_address_street " >< ? php esc_html_e ( 'Street Address' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< input type = " text " name = " wp_bnb_address_street " id = " wp_bnb_address_street "
value = " <?php echo esc_attr( get_option( 'wp_bnb_address_street', '' ) ); ?> "
class = " regular-text " >
</ td >
</ tr >
< tr >
< th scope = " row " >
< label for = " wp_bnb_address_city " >< ? php esc_html_e ( 'City' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< input type = " text " name = " wp_bnb_address_city " id = " wp_bnb_address_city "
value = " <?php echo esc_attr( get_option( 'wp_bnb_address_city', '' ) ); ?> "
class = " regular-text " >
</ td >
</ tr >
< tr >
< th scope = " row " >
< label for = " wp_bnb_address_postal " >< ? php esc_html_e ( 'Postal Code' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< input type = " text " name = " wp_bnb_address_postal " id = " wp_bnb_address_postal "
value = " <?php echo esc_attr( get_option( 'wp_bnb_address_postal', '' ) ); ?> "
class = " small-text " >
</ td >
</ tr >
< tr >
< th scope = " row " >
< label for = " wp_bnb_address_country " >< ? php esc_html_e ( 'Country' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< input type = " text " name = " wp_bnb_address_country " id = " wp_bnb_address_country "
value = " <?php echo esc_attr( get_option( 'wp_bnb_address_country', '' ) ); ?> "
class = " regular-text " >
</ td >
</ tr >
</ table >
< h2 >< ? php esc_html_e ( 'Contact Information' , 'wp-bnb' ); ?> </h2>
< table class = " form-table " role = " presentation " >
< tr >
< th scope = " row " >
< label for = " wp_bnb_contact_email " >< ? php esc_html_e ( 'Email Address' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< input type = " email " name = " wp_bnb_contact_email " id = " wp_bnb_contact_email "
value = " <?php echo esc_attr( get_option( 'wp_bnb_contact_email', '' ) ); ?> "
class = " regular-text " >
< p class = " description " >< ? php esc_html_e ( 'Primary contact email for bookings and inquiries.' , 'wp-bnb' ); ?> </p>
</ td >
</ tr >
< tr >
< th scope = " row " >
< label for = " wp_bnb_contact_phone " >< ? php esc_html_e ( 'Phone Number' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< input type = " tel " name = " wp_bnb_contact_phone " id = " wp_bnb_contact_phone "
value = " <?php echo esc_attr( get_option( 'wp_bnb_contact_phone', '' ) ); ?> "
class = " regular-text " placeholder = " +41 12 345 67 89 " >
</ td >
</ tr >
< tr >
< th scope = " row " >
< label for = " wp_bnb_contact_website " >< ? php esc_html_e ( 'Website' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< input type = " url " name = " wp_bnb_contact_website " id = " wp_bnb_contact_website "
value = " <?php echo esc_attr( get_option( 'wp_bnb_contact_website', '' ) ); ?> "
class = " regular-text " placeholder = " https:// " >
</ td >
</ tr >
</ table >
< h2 >< ? php esc_html_e ( 'Social Media' , 'wp-bnb' ); ?> </h2>
< table class = " form-table " role = " presentation " >
< tr >
< th scope = " row " >
< label for = " wp_bnb_social_facebook " >< ? php esc_html_e ( 'Facebook' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< input type = " url " name = " wp_bnb_social_facebook " id = " wp_bnb_social_facebook "
value = " <?php echo esc_attr( get_option( 'wp_bnb_social_facebook', '' ) ); ?> "
class = " regular-text " placeholder = " https://facebook.com/yourpage " >
</ td >
</ tr >
< tr >
< th scope = " row " >
< label for = " wp_bnb_social_instagram " >< ? php esc_html_e ( 'Instagram' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< input type = " url " name = " wp_bnb_social_instagram " id = " wp_bnb_social_instagram "
value = " <?php echo esc_attr( get_option( 'wp_bnb_social_instagram', '' ) ); ?> "
class = " regular-text " placeholder = " https://instagram.com/yourprofile " >
</ td >
</ tr >
< tr >
< th scope = " row " >
< label for = " wp_bnb_social_x " >< ? php esc_html_e ( 'X (Twitter)' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< input type = " url " name = " wp_bnb_social_x " id = " wp_bnb_social_x "
value = " <?php echo esc_attr( get_option( 'wp_bnb_social_x', '' ) ); ?> "
class = " regular-text " placeholder = " https://x.com/yourhandle " >
</ td >
</ tr >
< tr >
< th scope = " row " >
< label for = " wp_bnb_social_linkedin " >< ? php esc_html_e ( 'LinkedIn' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< input type = " url " name = " wp_bnb_social_linkedin " id = " wp_bnb_social_linkedin "
value = " <?php echo esc_attr( get_option( 'wp_bnb_social_linkedin', '' ) ); ?> "
class = " regular-text " placeholder = " https://linkedin.com/company/yourcompany " >
</ td >
</ tr >
< tr >
< th scope = " row " >
< label for = " wp_bnb_social_tripadvisor " >< ? php esc_html_e ( 'TripAdvisor' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< input type = " url " name = " wp_bnb_social_tripadvisor " id = " wp_bnb_social_tripadvisor "
value = " <?php echo esc_attr( get_option( 'wp_bnb_social_tripadvisor', '' ) ); ?> "
class = " regular-text " placeholder = " https://tripadvisor.com/... " >
< p class = " description " >< ? php esc_html_e ( 'Link to your TripAdvisor listing.' , 'wp-bnb' ); ?> </p>
</ td >
</ tr >
</ table >
2026-01-31 13:15:13 +01:00
< ? php submit_button ( __ ( 'Save Settings' , 'wp-bnb' ) ); ?>
</ form >
< ? php
}
2026-01-31 14:10:30 +01:00
/**
* Render pricing settings tab .
*
* @ return void
*/
private function render_pricing_settings () : void {
2026-02-03 15:18:27 +01:00
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Subtab switching only.
$active_subtab = isset ( $_GET [ 'subtab' ] ) ? sanitize_key ( $_GET [ 'subtab' ] ) : 'tiers' ;
2026-01-31 14:10:30 +01:00
$short_term_max = get_option ( 'wp_bnb_short_term_max_nights' , 6 );
$mid_term_max = get_option ( 'wp_bnb_mid_term_max_nights' , 27 );
$weekend_days = get_option ( 'wp_bnb_weekend_days' , '5,6' );
$seasons = Season :: all ();
2026-02-03 15:18:27 +01:00
$days_of_week = array (
2026-01-31 14:10:30 +01:00
1 => __ ( 'Monday' , 'wp-bnb' ),
2 => __ ( 'Tuesday' , 'wp-bnb' ),
3 => __ ( 'Wednesday' , 'wp-bnb' ),
4 => __ ( 'Thursday' , 'wp-bnb' ),
5 => __ ( 'Friday' , 'wp-bnb' ),
6 => __ ( 'Saturday' , 'wp-bnb' ),
7 => __ ( 'Sunday' , 'wp-bnb' ),
);
$selected_days = array_map ( 'intval' , explode ( ',' , $weekend_days ) );
2026-02-03 15:18:27 +01:00
$base_url = admin_url ( 'admin.php?page=wp-bnb-settings&tab=pricing' );
2026-01-31 14:10:30 +01:00
?>
2026-02-03 15:18:27 +01:00
<!-- Pricing Subtabs -->
< div class = " wp-bnb-subtabs " >
< a href = " <?php echo esc_url( $base_url . '&subtab=tiers' ); ?> "
class = " wp-bnb-subtab <?php echo 'tiers' === $active_subtab ? 'active' : ''; ?> " >
< span class = " dashicons dashicons-chart-bar " ></ span >
< ? php esc_html_e ( 'Pricing Tiers' , 'wp-bnb' ); ?>
</ a >
< a href = " <?php echo esc_url( $base_url . '&subtab=weekend' ); ?> "
class = " wp-bnb-subtab <?php echo 'weekend' === $active_subtab ? 'active' : ''; ?> " >
< span class = " dashicons dashicons-calendar-alt " ></ span >
< ? php esc_html_e ( 'Weekend Days' , 'wp-bnb' ); ?>
</ a >
< a href = " <?php echo esc_url( $base_url . '&subtab=seasons' ); ?> "
class = " wp-bnb-subtab <?php echo 'seasons' === $active_subtab ? 'active' : ''; ?> " >
< span class = " dashicons dashicons-image-filter " ></ span >
< ? php esc_html_e ( 'Seasons' , 'wp-bnb' ); ?>
</ a >
</ div >
2026-01-31 14:10:30 +01:00
< form method = " post " action = " " >
< ? php wp_nonce_field ( 'wp_bnb_save_settings' , 'wp_bnb_settings_nonce' ); ?>
2026-02-03 15:18:27 +01:00
< ? php if ( 'tiers' === $active_subtab ) : ?>
<!-- Pricing Tiers Subtab -->
< h2 >< ? php esc_html_e ( 'Pricing Tier Thresholds' , 'wp-bnb' ); ?> </h2>
< p class = " description " >< ? php esc_html_e ( 'Define the number of nights that determine which pricing tier applies.' , 'wp-bnb' ); ?> </p>
2026-01-31 14:10:30 +01:00
2026-02-03 15:18:27 +01:00
< table class = " form-table " role = " presentation " >
< tr >
< th scope = " row " >
< label for = " wp_bnb_short_term_max_nights " >< ? php esc_html_e ( 'Short-term (Nightly)' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< input type = " number " name = " wp_bnb_short_term_max_nights " id = " wp_bnb_short_term_max_nights "
value = " <?php echo esc_attr( $short_term_max ); ?> "
class = " small-text " min = " 1 " max = " 30 " >
< ? php esc_html_e ( 'nights or fewer' , 'wp-bnb' ); ?>
< p class = " description " >< ? php esc_html_e ( 'Stays up to this many nights use the nightly rate.' , 'wp-bnb' ); ?> </p>
</ td >
</ tr >
< tr >
< th scope = " row " >
< label for = " wp_bnb_mid_term_max_nights " >< ? php esc_html_e ( 'Mid-term (Weekly)' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< input type = " number " name = " wp_bnb_mid_term_max_nights " id = " wp_bnb_mid_term_max_nights "
value = " <?php echo esc_attr( $mid_term_max ); ?> "
class = " small-text " min = " 7 " max = " 90 " >
< ? php esc_html_e ( 'nights or fewer' , 'wp-bnb' ); ?>
< p class = " description " >< ? php esc_html_e ( 'Stays longer than short-term but up to this many nights use the weekly rate.' , 'wp-bnb' ); ?> </p>
</ td >
</ tr >
< tr >
< th scope = " row " >< ? php esc_html_e ( 'Long-term (Monthly)' , 'wp-bnb' ); ?> </th>
< td >
< p class = " description " >
< ? php
printf (
/* translators: %s: number of nights */
esc_html__ ( 'Stays longer than %s nights use the monthly rate.' , 'wp-bnb' ),
'<strong id="wp-bnb-long-term-min">' . esc_html ( $mid_term_max ) . '</strong>'
);
?>
</ p >
</ td >
</ tr >
</ table >
2026-01-31 14:10:30 +01:00
2026-02-03 15:18:27 +01:00
< ? php submit_button ( __ ( 'Save Pricing Tiers' , 'wp-bnb' ) ); ?>
2026-01-31 14:10:30 +01:00
2026-02-03 15:18:27 +01:00
< ? php elseif ( 'weekend' === $active_subtab ) : ?>
<!-- Weekend Days Subtab -->
< h2 >< ? php esc_html_e ( 'Weekend Days' , 'wp-bnb' ); ?> </h2>
< p class = " description " >< ? php esc_html_e ( 'Select which days are considered weekend days for weekend surcharges.' , 'wp-bnb' ); ?> </p>
2026-01-31 14:10:30 +01:00
2026-02-03 15:18:27 +01:00
< table class = " form-table " role = " presentation " >
< tr >
< th scope = " row " >< ? php esc_html_e ( 'Weekend Days' , 'wp-bnb' ); ?> </th>
< td >
< fieldset >
< ? php foreach ( $days_of_week as $day_num => $day_name ) : ?>
< label style = " display: inline-block; margin-right: 15px; " >
< input type = " checkbox " name = " wp_bnb_weekend_days[] " value = " <?php echo esc_attr( $day_num ); ?> "
< ? php checked ( in_array ( $day_num , $selected_days , true ) ); ?> >
< ? php echo esc_html ( $day_name ); ?>
</ label >
< ? php endforeach ; ?>
</ fieldset >
< p class = " description " >< ? php esc_html_e ( 'Weekend surcharges (configured per room) apply to nights starting on these days.' , 'wp-bnb' ); ?> </p>
</ td >
</ tr >
</ table >
< ? php submit_button ( __ ( 'Save Weekend Days' , 'wp-bnb' ) ); ?>
2026-01-31 14:10:30 +01:00
2026-02-03 15:18:27 +01:00
< ? php else : ?>
<!-- Seasons Subtab -->
< h2 >< ? php esc_html_e ( 'Seasonal Pricing' , 'wp-bnb' ); ?> </h2>
< p class = " description " >
< ? php esc_html_e ( 'Seasonal pricing allows you to adjust room rates based on time of year. Prices are multiplied by the season modifier.' , 'wp-bnb' ); ?>
</ p >
< p >
< a href = " <?php echo esc_url( admin_url( 'admin.php?page=wp-bnb-seasons' ) ); ?> " class = " button button-primary " >
< span class = " dashicons dashicons-admin-settings " style = " vertical-align: text-top; " ></ span >
< ? php esc_html_e ( 'Manage Seasons' , 'wp-bnb' ); ?>
</ a >
</ p >
< ? php if ( ! empty ( $seasons ) ) : ?>
< table class = " widefat striped " style = " max-width: 700px; margin-top: 20px; " >
< thead >
2026-01-31 14:10:30 +01:00
< tr >
2026-02-03 15:18:27 +01:00
< th >< ? php esc_html_e ( 'Season' , 'wp-bnb' ); ?> </th>
< th >< ? php esc_html_e ( 'Period' , 'wp-bnb' ); ?> </th>
< th >< ? php esc_html_e ( 'Modifier' , 'wp-bnb' ); ?> </th>
< th >< ? php esc_html_e ( 'Priority' , 'wp-bnb' ); ?> </th>
< th >< ? php esc_html_e ( 'Status' , 'wp-bnb' ); ?> </th>
2026-01-31 14:10:30 +01:00
</ tr >
2026-02-03 15:18:27 +01:00
</ thead >
< tbody >
< ? php foreach ( $seasons as $season ) : ?>
< tr >
< td >< strong >< ? php echo esc_html ( $season -> name ); ?> </strong></td>
< td >< ? php echo esc_html ( $season -> start_date . ' - ' . $season -> end_date ); ?> </td>
< td >< ? php echo esc_html ( $season -> getModifierLabel () ); ?> </td>
< td >< ? php echo esc_html ( $season -> priority ); ?> </td>
< td >
< ? php if ( $season -> active ) : ?>
< span class = " bnb-status-active " >< ? php esc_html_e ( 'Active' , 'wp-bnb' ); ?> </span>
< ? php else : ?>
< span class = " bnb-status-inactive " >< ? php esc_html_e ( 'Inactive' , 'wp-bnb' ); ?> </span>
< ? php endif ; ?>
</ td >
</ tr >
< ? php endforeach ; ?>
</ tbody >
</ table >
< ? php else : ?>
< div class = " notice notice-info inline " style = " margin: 20px 0; " >
< p >< ? php esc_html_e ( 'No seasons configured yet. Create seasons to apply price modifiers during specific periods.' , 'wp-bnb' ); ?> </p>
</ div >
< ? php endif ; ?>
2026-01-31 14:10:30 +01:00
2026-02-03 15:18:27 +01:00
< ? php endif ; ?>
2026-01-31 14:10:30 +01:00
</ form >
< ? php
}
2026-01-31 13:15:13 +01:00
/**
* Render license settings tab .
*
* @ return void
*/
private function render_license_settings () : void {
$license_key = LicenseManager :: get_license_key ();
$server_url = LicenseManager :: get_server_url ();
$license_status = LicenseManager :: get_cached_status ();
$license_data = LicenseManager :: get_cached_data ();
$last_check = LicenseManager :: get_last_check ();
2026-02-03 15:18:27 +01:00
$is_localhost = LicenseManager :: is_localhost ();
2026-01-31 13:15:13 +01:00
?>
< form method = " post " action = " " >
< ? php wp_nonce_field ( 'wp_bnb_save_settings' , 'wp_bnb_settings_nonce' ); ?>
2026-02-03 15:18:27 +01:00
< ? php if ( $is_localhost ) : ?>
< div class = " notice notice-info inline " style = " margin: 0 0 20px 0; " >
< p >
< span class = " dashicons dashicons-info " style = " color: #72aee6; " ></ span >
< strong >< ? php esc_html_e ( 'Development Mode' , 'wp-bnb' ); ?> </strong>
< ? php esc_html_e ( 'You are running on a local development environment. License validation is bypassed and all features are enabled.' , 'wp-bnb' ); ?>
</ p >
</ div >
< ? php endif ; ?>
2026-01-31 13:15:13 +01:00
< h2 >< ? php esc_html_e ( 'License Status' , 'wp-bnb' ); ?> </h2>
< table class = " form-table " role = " presentation " >
< tr >
< th scope = " row " >< ? php esc_html_e ( 'Status' , 'wp-bnb' ); ?> </th>
< td >
< ? php $this -> render_license_status_badge ( $license_status ); ?>
< ? php if ( $last_check > 0 ) : ?>
< p class = " description " >
< ? php
printf (
/* translators: %s: Time ago string */
esc_html__ ( 'Last checked: %s' , 'wp-bnb' ),
esc_html ( human_time_diff ( $last_check , time () ) . ' ' . __ ( 'ago' , 'wp-bnb' ) )
);
?>
</ p >
< ? php endif ; ?>
</ td >
</ tr >
< ? php if ( ! empty ( $license_data [ 'expires' ] ) ) : ?>
< tr >
< th scope = " row " >< ? php esc_html_e ( 'Expires' , 'wp-bnb' ); ?> </th>
< td >
< ? php echo esc_html ( wp_date ( get_option ( 'date_format' ), strtotime ( $license_data [ 'expires' ] ) ) ); ?>
</ td >
</ tr >
< ? php endif ; ?>
</ table >
< h2 >< ? php esc_html_e ( 'License Configuration' , 'wp-bnb' ); ?> </h2>
< table class = " form-table " role = " presentation " >
< tr >
< th scope = " row " >
< label for = " wp_bnb_license_server_url " >< ? php esc_html_e ( 'License Server URL' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< input type = " url " name = " wp_bnb_license_server_url " id = " wp_bnb_license_server_url "
value = " <?php echo esc_attr( $server_url ); ?> "
class = " regular-text " placeholder = " https://example.com " >
< p class = " description " >< ? php esc_html_e ( 'The URL of the license server.' , 'wp-bnb' ); ?> </p>
</ td >
</ tr >
< tr >
< th scope = " row " >
< label for = " wp_bnb_license_key " >< ? php esc_html_e ( 'License Key' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< input type = " text " name = " wp_bnb_license_key " id = " wp_bnb_license_key "
value = " <?php echo esc_attr( $license_key ); ?> "
class = " regular-text " placeholder = " XXXX-XXXX-XXXX-XXXX " >
< p class = " description " >< ? php esc_html_e ( 'Your license key from the purchase confirmation email.' , 'wp-bnb' ); ?> </p>
</ td >
</ tr >
< tr >
< th scope = " row " >
< label for = " wp_bnb_license_server_secret " >< ? php esc_html_e ( 'Server Secret' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< input type = " password " name = " wp_bnb_license_server_secret " id = " wp_bnb_license_server_secret "
value = " " class = " regular-text "
placeholder = " <?php echo ! empty( LicenseManager::get_server_secret() ) ? '••••••••••••••••' : ''; ?> " >
< p class = " description " >< ? php esc_html_e ( 'Leave empty to keep the current secret. The shared secret for secure communication.' , 'wp-bnb' ); ?> </p>
</ td >
</ tr >
</ table >
< p class = " submit " >
< ? php submit_button ( __ ( 'Save License Settings' , 'wp-bnb' ), 'primary' , 'submit' , false ); ?>
< button type = " button " id = " wp-bnb-validate-license " class = " button button-secondary " >
< ? php esc_html_e ( 'Validate License' , 'wp-bnb' ); ?>
</ button >
< button type = " button " id = " wp-bnb-activate-license " class = " button button-secondary " >
< ? php esc_html_e ( 'Activate License' , 'wp-bnb' ); ?>
</ button >
< span class = " spinner " id = " wp-bnb-license-spinner " ></ span >
</ p >
< div id = " wp-bnb-license-message " style = " display: none; " ></ div >
</ form >
< ? php
}
2026-02-03 15:18:27 +01:00
/**
* Render updates settings tab .
*
* @ return void
*/
private function render_updates_settings () : void {
$updater = LicenseUpdater :: get_instance ();
if ( null === $updater ) {
?>
< p >< ? php esc_html_e ( 'Update checker is not available.' , 'wp-bnb' ); ?> </p>
< ? php
return ;
}
$current_version = $updater -> get_current_version ();
$last_check = LicenseUpdater :: get_last_check ();
$update_info = $updater -> get_cached_update_info ();
$update_available = false ;
$latest_version = $current_version ;
$notifications_enabled = LicenseUpdater :: is_notifications_enabled ();
$auto_install_enabled = LicenseUpdater :: is_auto_install_enabled ();
$check_frequency = LicenseUpdater :: get_check_frequency ();
$license_valid = LicenseManager :: is_license_valid ();
if ( $update_info instanceof UpdateInfo && $update_info -> updateAvailable ) {
$latest_version = $update_info -> version ? ? $current_version ;
$update_available = version_compare ( $current_version , $latest_version , '<' );
}
?>
< form method = " post " action = " " >
< ? php wp_nonce_field ( 'wp_bnb_save_settings' , 'wp_bnb_settings_nonce' ); ?>
< h2 >< ? php esc_html_e ( 'Update Status' , 'wp-bnb' ); ?> </h2>
< table class = " form-table " role = " presentation " >
< tr >
< th scope = " row " >< ? php esc_html_e ( 'Current Version' , 'wp-bnb' ); ?> </th>
< td >
< strong >< ? php echo esc_html ( $current_version ); ?> </strong>
</ td >
</ tr >
< tr >
< th scope = " row " >< ? php esc_html_e ( 'Latest Version' , 'wp-bnb' ); ?> </th>
< td >
< span id = " wp-bnb-latest-version " >
< ? php if ( $update_available ) : ?>
< span style = " color: #00a32a; font-weight: 600; " >
< ? php echo esc_html ( $latest_version ); ?>
</ span >
< span class = " dashicons dashicons-yes " style = " color: #00a32a; " ></ span >
< em >< ? php esc_html_e ( 'Update available!' , 'wp-bnb' ); ?> </em>
< ? php else : ?>
< ? php echo esc_html ( $latest_version ); ?>
< span style = " color: #646970; " >
< ? php esc_html_e ( '(You are up to date)' , 'wp-bnb' ); ?>
</ span >
< ? php endif ; ?>
</ span >
</ td >
</ tr >
< tr >
< th scope = " row " >< ? php esc_html_e ( 'Last Check' , 'wp-bnb' ); ?> </th>
< td >
< span id = " wp-bnb-update-last-check " >
< ? php if ( $last_check > 0 ) : ?>
< ? php
printf (
/* translators: %s: Time ago string */
esc_html__ ( '%s ago' , 'wp-bnb' ),
esc_html ( human_time_diff ( $last_check , time () ) )
);
?>
< ? php else : ?>
< ? php esc_html_e ( 'Never' , 'wp-bnb' ); ?>
< ? php endif ; ?>
</ span >
</ td >
</ tr >
</ table >
< p style = " margin-bottom: 30px; " >
< button type = " button " id = " wp-bnb-check-updates " class = " button button-secondary " >
< span class = " dashicons dashicons-update " style = " vertical-align: text-top; " ></ span >
< ? php esc_html_e ( 'Check for Updates' , 'wp-bnb' ); ?>
</ button >
< span class = " spinner " id = " wp-bnb-update-spinner " ></ span >
< ? php if ( $update_available ) : ?>
< a href = " <?php echo esc_url( admin_url( 'plugins.php' ) ); ?> " class = " button button-primary " >
< ? php esc_html_e ( 'Go to Plugins Page' , 'wp-bnb' ); ?>
</ a >
< ? php endif ; ?>
</ p >
< div id = " wp-bnb-update-message " style = " display: none; margin-bottom: 20px; " ></ div >
< h2 >< ? php esc_html_e ( 'Update Settings' , 'wp-bnb' ); ?> </h2>
< table class = " form-table " role = " presentation " >
< tr >
< th scope = " row " >< ? php esc_html_e ( 'Enable Update Notifications' , 'wp-bnb' ); ?> </th>
< td >
< label >
< input type = " checkbox " name = " wp_bnb_update_notifications_enabled "
value = " yes " < ? php checked ( $notifications_enabled ); ?> >
< ? php esc_html_e ( 'Check for updates from the license server' , 'wp-bnb' ); ?>
</ label >
< p class = " description " >
< ? php esc_html_e ( 'When enabled, the plugin will check for updates and show notifications in the WordPress admin.' , 'wp-bnb' ); ?>
</ p >
</ td >
</ tr >
< tr >
< th scope = " row " >< ? php esc_html_e ( 'Automatic Updates' , 'wp-bnb' ); ?> </th>
< td >
< label >
< input type = " checkbox " name = " wp_bnb_auto_install_enabled "
value = " yes " < ? php checked ( $auto_install_enabled ); ?>
< ? php disabled ( ! $license_valid ); ?> >
< ? php esc_html_e ( 'Automatically install updates' , 'wp-bnb' ); ?>
</ label >
< ? php if ( ! $license_valid ) : ?>
< span style = " color: #d63638; margin-left: 10px; " >
< ? php esc_html_e ( '(Requires valid license)' , 'wp-bnb' ); ?>
</ span >
< ? php endif ; ?>
< p class = " description " >
< ? php esc_html_e ( 'When enabled, updates will be automatically installed during WordPress background updates.' , 'wp-bnb' ); ?>
</ p >
</ td >
</ tr >
< tr >
< th scope = " row " >
< label for = " wp_bnb_update_check_frequency " >< ? php esc_html_e ( 'Check Frequency' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< input type = " number " name = " wp_bnb_update_check_frequency " id = " wp_bnb_update_check_frequency "
value = " <?php echo esc_attr( $check_frequency ); ?> "
min = " 1 " max = " 168 " class = " small-text " >
< ? php esc_html_e ( 'hours' , 'wp-bnb' ); ?>
< p class = " description " >
< ? php esc_html_e ( 'How often to check for updates (1-168 hours). Default: 12 hours.' , 'wp-bnb' ); ?>
</ p >
</ td >
</ tr >
</ table >
< p class = " submit " >
< ? php submit_button ( __ ( 'Save Update Settings' , 'wp-bnb' ), 'primary' , 'submit' , false ); ?>
</ p >
</ form >
< ? php
}
2026-02-03 20:40:54 +01:00
/**
* Render metrics settings tab .
*
* @ return void
*/
private function render_metrics_settings () : void {
$metrics_enabled = Prometheus :: is_enabled ();
$prometheus_active = class_exists ( '\Magdev\WpPrometheus\Plugin' ) || defined ( 'WP_PROMETHEUS_VERSION' );
$dashboard_file = WP_BNB_PATH . 'assets/grafana/wp-bnb-dashboard.json' ;
$dashboard_available = file_exists ( $dashboard_file );
?>
< form method = " post " action = " " >
< ? php wp_nonce_field ( 'wp_bnb_save_settings' , 'wp_bnb_settings_nonce' ); ?>
< h2 >< ? php esc_html_e ( 'Prometheus Metrics' , 'wp-bnb' ); ?> </h2>
< ? php if ( ! $prometheus_active ) : ?>
< div class = " notice notice-warning inline " style = " margin: 0 0 20px 0; " >
< p >
< span class = " dashicons dashicons-warning " style = " color: #dba617; " ></ span >
< strong >< ? php esc_html_e ( 'WP Prometheus not detected' , 'wp-bnb' ); ?> </strong><br>
< ? php
printf (
/* translators: %s: Plugin URL */
esc_html__ ( 'The WP Prometheus plugin is required to expose metrics. Please install and activate it from %s.' , 'wp-bnb' ),
'<a href="https://src.bundespruefstelle.ch/magdev/wp-prometheus" target="_blank">wp-prometheus</a>'
);
?>
</ p >
</ div >
< ? php else : ?>
< div class = " notice notice-success inline " style = " margin: 0 0 20px 0; " >
< p >
< span class = " dashicons dashicons-yes-alt " style = " color: #00a32a; " ></ span >
< strong >< ? php esc_html_e ( 'WP Prometheus is active' , 'wp-bnb' ); ?> </strong>
< ? php esc_html_e ( 'Metrics will be exposed via the /metrics/ endpoint.' , 'wp-bnb' ); ?>
</ p >
</ div >
< ? php endif ; ?>
< table class = " form-table " role = " presentation " >
< tr >
< th scope = " row " >< ? php esc_html_e ( 'Enable Metrics' , 'wp-bnb' ); ?> </th>
< td >
< label >
< input type = " checkbox " name = " wp_bnb_metrics_enabled "
value = " yes " < ? php checked ( $metrics_enabled ); ?> >
< ? php esc_html_e ( 'Expose BnB metrics via Prometheus' , 'wp-bnb' ); ?>
</ label >
< p class = " description " >
< ? php esc_html_e ( 'When enabled, occupancy, booking, revenue, and guest metrics will be available for Prometheus scraping.' , 'wp-bnb' ); ?>
</ p >
</ td >
</ tr >
</ table >
< h2 >< ? php esc_html_e ( 'Available Metrics' , 'wp-bnb' ); ?> </h2>
< p class = " description " >< ? php esc_html_e ( 'The following metrics are exposed when enabled:' , 'wp-bnb' ); ?> </p>
< table class = " widefat striped " style = " max-width: 800px; margin-top: 10px; " >
< thead >
< tr >
< th >< ? php esc_html_e ( 'Metric' , 'wp-bnb' ); ?> </th>
< th >< ? php esc_html_e ( 'Type' , 'wp-bnb' ); ?> </th>
< th >< ? php esc_html_e ( 'Description' , 'wp-bnb' ); ?> </th>
</ tr >
</ thead >
< tbody >
< tr >
< td >< code > wp_bnb_buildings_total </ code ></ td >
< td >< ? php esc_html_e ( 'Gauge' , 'wp-bnb' ); ?> </td>
< td >< ? php esc_html_e ( 'Total number of buildings' , 'wp-bnb' ); ?> </td>
</ tr >
< tr >
< td >< code > wp_bnb_rooms_total </ code ></ td >
< td >< ? php esc_html_e ( 'Gauge' , 'wp-bnb' ); ?> </td>
< td >< ? php esc_html_e ( 'Total rooms by status (available, occupied, maintenance, inactive)' , 'wp-bnb' ); ?> </td>
</ tr >
< tr >
< td >< code > wp_bnb_bookings_total </ code ></ td >
< td >< ? php esc_html_e ( 'Gauge' , 'wp-bnb' ); ?> </td>
< td >< ? php esc_html_e ( 'Total bookings by status (pending, confirmed, checked_in, checked_out, cancelled)' , 'wp-bnb' ); ?> </td>
</ tr >
< tr >
< td >< code > wp_bnb_occupancy_rate_current </ code ></ td >
< td >< ? php esc_html_e ( 'Gauge' , 'wp-bnb' ); ?> </td>
< td >< ? php esc_html_e ( 'Current room occupancy rate (percentage)' , 'wp-bnb' ); ?> </td>
</ tr >
< tr >
< td >< code > wp_bnb_occupancy_rate_this_month </ code ></ td >
< td >< ? php esc_html_e ( 'Gauge' , 'wp-bnb' ); ?> </td>
< td >< ? php esc_html_e ( 'Room occupancy rate for current month (percentage)' , 'wp-bnb' ); ?> </td>
</ tr >
< tr >
< td >< code > wp_bnb_checkins_today </ code ></ td >
< td >< ? php esc_html_e ( 'Gauge' , 'wp-bnb' ); ?> </td>
< td >< ? php esc_html_e ( 'Number of check-ins scheduled for today' , 'wp-bnb' ); ?> </td>
</ tr >
< tr >
< td >< code > wp_bnb_checkouts_today </ code ></ td >
< td >< ? php esc_html_e ( 'Gauge' , 'wp-bnb' ); ?> </td>
< td >< ? php esc_html_e ( 'Number of check-outs scheduled for today' , 'wp-bnb' ); ?> </td>
</ tr >
< tr >
< td >< code > wp_bnb_revenue_this_month </ code ></ td >
< td >< ? php esc_html_e ( 'Gauge' , 'wp-bnb' ); ?> </td>
< td >< ? php esc_html_e ( 'Total revenue for current month' , 'wp-bnb' ); ?> </td>
</ tr >
< tr >
< td >< code > wp_bnb_revenue_ytd </ code ></ td >
< td >< ? php esc_html_e ( 'Gauge' , 'wp-bnb' ); ?> </td>
< td >< ? php esc_html_e ( 'Total revenue year to date' , 'wp-bnb' ); ?> </td>
</ tr >
< tr >
< td >< code > wp_bnb_booking_avg_value </ code ></ td >
< td >< ? php esc_html_e ( 'Gauge' , 'wp-bnb' ); ?> </td>
< td >< ? php esc_html_e ( 'Average booking value' , 'wp-bnb' ); ?> </td>
</ tr >
< tr >
< td >< code > wp_bnb_guests_total </ code ></ td >
< td >< ? php esc_html_e ( 'Gauge' , 'wp-bnb' ); ?> </td>
< td >< ? php esc_html_e ( 'Total number of registered guests' , 'wp-bnb' ); ?> </td>
</ tr >
< tr >
< td >< code > wp_bnb_guests_repeat </ code ></ td >
< td >< ? php esc_html_e ( 'Gauge' , 'wp-bnb' ); ?> </td>
< td >< ? php esc_html_e ( 'Number of repeat guests (more than one booking)' , 'wp-bnb' ); ?> </td>
</ tr >
</ tbody >
</ table >
< h2 style = " margin-top: 30px; " >< ? php esc_html_e ( 'Grafana Dashboard' , 'wp-bnb' ); ?> </h2>
< ? php if ( $dashboard_available ) : ?>
< p >
< ? php esc_html_e ( 'A pre-configured Grafana dashboard is available for visualizing WP BnB metrics.' , 'wp-bnb' ); ?>
</ p >
< p >
< strong >< ? php esc_html_e ( 'Dashboard file:' , 'wp-bnb' ); ?> </strong>
< code > assets / grafana / wp - bnb - dashboard . json </ code >
</ p >
< p class = " description " >
< ? php esc_html_e ( 'If WP Prometheus is installed, this dashboard will be automatically registered and available for export in the Prometheus settings.' , 'wp-bnb' ); ?>
</ p >
< ? php else : ?>
< div class = " notice notice-warning inline " >
< p >< ? php esc_html_e ( 'Grafana dashboard file not found.' , 'wp-bnb' ); ?> </p>
</ div >
< ? php endif ; ?>
< p class = " submit " >
< ? php submit_button ( __ ( 'Save Metrics Settings' , 'wp-bnb' ), 'primary' , 'submit' , false ); ?>
</ p >
</ form >
< ? php
}
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
/**
* Render API settings tab .
*
* @ return void
*/
private function render_api_settings () : void {
2026-02-03 21:50:12 +01:00
// 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' );
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
?>
2026-02-03 21:50:12 +01:00
<!-- API Subtabs -->
< div class = " wp-bnb-subtabs " >
< a href = " <?php echo esc_url( $base_url . '&subtab=general' ); ?> "
class = " wp-bnb-subtab <?php echo 'general' === $active_subtab ? 'active' : ''; ?> " >
< span class = " dashicons dashicons-admin-generic " ></ span >
< ? php esc_html_e ( 'General' , 'wp-bnb' ); ?>
</ a >
< a href = " <?php echo esc_url( $base_url . '&subtab=rate-limits' ); ?> "
class = " wp-bnb-subtab <?php echo 'rate-limits' === $active_subtab ? 'active' : ''; ?> " >
< span class = " dashicons dashicons-dashboard " ></ span >
< ? php esc_html_e ( 'Rate Limits' , 'wp-bnb' ); ?>
</ a >
< a href = " <?php echo esc_url( $base_url . '&subtab=endpoints' ); ?> "
class = " wp-bnb-subtab <?php echo 'endpoints' === $active_subtab ? 'active' : ''; ?> " >
< span class = " dashicons dashicons-rest-api " ></ span >
< ? php esc_html_e ( 'Endpoints' , 'wp-bnb' ); ?>
</ a >
</ div >
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
< form method = " post " action = " " >
< ? php wp_nonce_field ( 'wp_bnb_save_settings' , 'wp_bnb_settings_nonce' ); ?>
2026-02-03 21:50:12 +01:00
< ? php if ( 'general' === $active_subtab ) : ?>
<!-- General Subtab -->
< h2 >< ? php esc_html_e ( 'REST API Settings' , 'wp-bnb' ); ?> </h2>
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
2026-02-03 21:50:12 +01:00
< table class = " form-table " >
< tr >
< th scope = " row " >< ? php esc_html_e ( 'Enable API' , 'wp-bnb' ); ?> </th>
< td >
< label >
< input type = " checkbox " name = " wp_bnb_api_enabled " value = " yes " < ? php checked ( $api_enabled , 'yes' ); ?> >
< ? php esc_html_e ( 'Enable the REST API endpoints' , 'wp-bnb' ); ?>
</ label >
< p class = " description " >
< ? php esc_html_e ( 'When enabled, external applications can access room, availability, and booking data via the API.' , 'wp-bnb' ); ?>
</ p >
</ td >
</ tr >
< tr >
< th scope = " row " >< ? php esc_html_e ( 'Rate Limiting' , 'wp-bnb' ); ?> </th>
< td >
< label >
< input type = " checkbox " name = " wp_bnb_api_rate_limiting " value = " yes " < ? php checked ( $rate_limiting , 'yes' ); ?> >
< ? php esc_html_e ( 'Enable rate limiting' , 'wp-bnb' ); ?>
</ label >
< p class = " description " >
< ? php esc_html_e ( 'Limits API requests to prevent abuse. Recommended for production sites.' , 'wp-bnb' ); ?>
< ? php if ( 'yes' === $rate_limiting ) : ?>
< a href = " <?php echo esc_url( $base_url . '&subtab=rate-limits' ); ?> " >< ? php esc_html_e ( 'Configure limits' , 'wp-bnb' ); ?> →</a>
< ? php endif ; ?>
</ p >
</ td >
</ tr >
</ table >
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
2026-02-03 21:50:12 +01:00
< h2 style = " margin-top: 30px; " >< ? php esc_html_e ( 'API Information' , 'wp-bnb' ); ?> </h2>
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
2026-02-03 21:50:12 +01:00
< table class = " form-table " >
< tr >
< th scope = " row " >< ? php esc_html_e ( 'Base URL' , 'wp-bnb' ); ?> </th>
< td >
< code >< ? php echo esc_html ( $api_base_url ); ?> </code>
< p class = " description " >
< ? php esc_html_e ( 'All API endpoints are prefixed with this URL.' , 'wp-bnb' ); ?>
</ p >
</ td >
</ tr >
< tr >
< th scope = " row " >< ? php esc_html_e ( 'API Version' , 'wp-bnb' ); ?> </th>
< td >
< code >< ? php echo esc_html ( RestApi :: VERSION ); ?> </code>
</ td >
</ tr >
< tr >
< th scope = " row " >< ? php esc_html_e ( 'Info Endpoint' , 'wp-bnb' ); ?> </th>
< td >
< code >< ? php echo esc_html ( $api_base_url . '/info' ); ?> </code>
< p class = " description " >
< ? php esc_html_e ( 'Returns API information and available endpoints.' , 'wp-bnb' ); ?>
</ p >
</ td >
</ tr >
</ table >
< ? php submit_button ( __ ( 'Save Settings' , 'wp-bnb' ) ); ?>
< ? php elseif ( 'rate-limits' === $active_subtab ) : ?>
<!-- Rate Limits Subtab -->
< h2 >< ? php esc_html_e ( 'Rate Limit Configuration' , 'wp-bnb' ); ?> </h2>
< ? php if ( 'yes' !== $rate_limiting ) : ?>
< div class = " notice notice-warning inline " style = " margin: 15px 0; " >
< p >
< ? php esc_html_e ( 'Rate limiting is currently disabled.' , 'wp-bnb' ); ?>
< a href = " <?php echo esc_url( $base_url . '&subtab=general' ); ?> " >< ? php esc_html_e ( 'Enable it in General settings' , 'wp-bnb' ); ?> </a>
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
</ p >
2026-02-03 21:50:12 +01:00
</ div >
< ? php endif ; ?>
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
2026-02-03 21:50:12 +01:00
< p class = " description " >< ? php esc_html_e ( 'Configure the number of requests allowed per time window for each endpoint type.' , 'wp-bnb' ); ?> </p>
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
2026-02-03 21:50:12 +01:00
< table class = " form-table " >
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
< tr >
2026-02-03 21:50:12 +01:00
< th scope = " row " >< ? php esc_html_e ( 'Time Window' , 'wp-bnb' ); ?> </th>
< td >
< input type = " number " name = " wp_bnb_rate_limit_window " value = " <?php echo esc_attr( $limit_window ); ?> " min = " 10 " max = " 300 " step = " 10 " class = " small-text " >
< ? php esc_html_e ( 'seconds' , 'wp-bnb' ); ?>
< p class = " description " >
< ? php esc_html_e ( 'The time window for rate limit counting. Default: 60 seconds.' , 'wp-bnb' ); ?>
</ p >
</ td >
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
</ tr >
< tr >
2026-02-03 21:50:12 +01:00
< th scope = " row " >< ? php esc_html_e ( 'Public Endpoints' , 'wp-bnb' ); ?> </th>
< td >
< input type = " number " name = " wp_bnb_rate_limit_public " value = " <?php echo esc_attr( $limit_public ); ?> " min = " 1 " max = " 1000 " class = " small-text " >
< ? php esc_html_e ( 'requests per window' , 'wp-bnb' ); ?>
< p class = " description " >
< ? php
printf (
/* translators: %d: default limit */
esc_html__ ( 'Limit for public read endpoints (rooms, buildings, services). Default: %d' , 'wp-bnb' ),
$defaults [ 'public' ]
);
?>
</ p >
</ td >
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
</ tr >
2026-02-03 21:50:12 +01:00
< tr >
< th scope = " row " >< ? php esc_html_e ( 'Availability Endpoints' , 'wp-bnb' ); ?> </th>
< td >
< input type = " number " name = " wp_bnb_rate_limit_availability " value = " <?php echo esc_attr( $limit_avail ); ?> " min = " 1 " max = " 1000 " class = " small-text " >
< ? php esc_html_e ( 'requests per window' , 'wp-bnb' ); ?>
< p class = " description " >
< ? php
printf (
/* translators: %d: default limit */
esc_html__ ( 'Limit for availability checks and calendar requests. Default: %d' , 'wp-bnb' ),
$defaults [ 'availability' ]
);
?>
</ p >
</ td >
</ tr >
< tr >
< th scope = " row " >< ? php esc_html_e ( 'Booking Endpoints' , 'wp-bnb' ); ?> </th>
< td >
< input type = " number " name = " wp_bnb_rate_limit_booking " value = " <?php echo esc_attr( $limit_booking ); ?> " min = " 1 " max = " 100 " class = " small-text " >
< ? php esc_html_e ( 'requests per window' , 'wp-bnb' ); ?>
< p class = " description " >
< ? php
printf (
/* translators: %d: default limit */
esc_html__ ( 'Limit for booking creation. Keep low to prevent abuse. Default: %d' , 'wp-bnb' ),
$defaults [ 'booking' ]
);
?>
</ p >
</ td >
</ tr >
< tr >
< th scope = " row " >< ? php esc_html_e ( 'Admin Endpoints' , 'wp-bnb' ); ?> </th>
< td >
< input type = " number " name = " wp_bnb_rate_limit_admin " value = " <?php echo esc_attr( $limit_admin ); ?> " min = " 1 " max = " 1000 " class = " small-text " >
< ? php esc_html_e ( 'requests per window' , 'wp-bnb' ); ?>
< p class = " description " >
< ? php
printf (
/* translators: %d: default limit */
esc_html__ ( 'Limit for authenticated admin endpoints. Default: %d' , 'wp-bnb' ),
$defaults [ 'admin' ]
);
?>
</ p >
</ td >
</ tr >
</ table >
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
2026-02-03 21:50:12 +01:00
< h2 style = " margin-top: 30px; " >< ? php esc_html_e ( 'Current Rate Limits Summary' , 'wp-bnb' ); ?> </h2>
< table class = " widefat striped " style = " max-width: 600px; " >
< thead >
< tr >
< th >< ? php esc_html_e ( 'Type' , 'wp-bnb' ); ?> </th>
< th >< ? php esc_html_e ( 'Limit' , 'wp-bnb' ); ?> </th>
< th >< ? php esc_html_e ( 'Applies To' , 'wp-bnb' ); ?> </th>
</ tr >
</ thead >
< tbody >
< tr >
< td >< ? php esc_html_e ( 'Public' , 'wp-bnb' ); ?> </td>
< td >< strong >< ? php echo esc_html ( $limit_public . '/' . $limit_window . 's' ); ?> </strong></td>
< td >< ? php esc_html_e ( 'GET rooms, buildings, services' , 'wp-bnb' ); ?> </td>
</ tr >
< tr >
< td >< ? php esc_html_e ( 'Availability' , 'wp-bnb' ); ?> </td>
< td >< strong >< ? php echo esc_html ( $limit_avail . '/' . $limit_window . 's' ); ?> </strong></td>
< td >< ? php esc_html_e ( 'Availability checks, calendar' , 'wp-bnb' ); ?> </td>
</ tr >
< tr >
< td >< ? php esc_html_e ( 'Booking' , 'wp-bnb' ); ?> </td>
< td >< strong >< ? php echo esc_html ( $limit_booking . '/' . $limit_window . 's' ); ?> </strong></td>
< td >< ? php esc_html_e ( 'Booking creation' , 'wp-bnb' ); ?> </td>
</ tr >
< tr >
< td >< ? php esc_html_e ( 'Admin' , 'wp-bnb' ); ?> </td>
< td >< strong >< ? php echo esc_html ( $limit_admin . '/' . $limit_window . 's' ); ?> </strong></td>
< td >< ? php esc_html_e ( 'All admin endpoints' , 'wp-bnb' ); ?> </td>
</ tr >
</ tbody >
</ table >
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
2026-02-03 21:50:12 +01:00
< ? php submit_button ( __ ( 'Save Rate Limits' , 'wp-bnb' ) ); ?>
< ? php else : ?>
<!-- Endpoints Subtab -->
< h2 >< ? php esc_html_e ( 'Available Endpoints' , 'wp-bnb' ); ?> </h2>
< h3 >< ? php esc_html_e ( 'Public Endpoints' , 'wp-bnb' ); ?> </h3>
< p class = " description " >< ? php esc_html_e ( 'These endpoints are accessible without authentication.' , 'wp-bnb' ); ?> </p>
< table class = " widefat striped " style = " margin-bottom: 20px; " >
< thead >
< tr >
< th style = " width: 80px; " >< ? php esc_html_e ( 'Method' , 'wp-bnb' ); ?> </th>
< th style = " width: 250px; " >< ? php esc_html_e ( 'Endpoint' , 'wp-bnb' ); ?> </th>
< th >< ? php esc_html_e ( 'Description' , 'wp-bnb' ); ?> </th>
</ tr >
</ thead >
< tbody >
< tr >< td >< span class = " wp-bnb-method get " > GET </ span ></ td >< td >< code >/ buildings </ code ></ td >< td >< ? php esc_html_e ( 'List all buildings' , 'wp-bnb' ); ?> </td></tr>
< tr >< td >< span class = " wp-bnb-method get " > GET </ span ></ td >< td >< code >/ buildings / { id } </ code ></ td >< td >< ? php esc_html_e ( 'Get building details' , 'wp-bnb' ); ?> </td></tr>
< tr >< td >< span class = " wp-bnb-method get " > GET </ span ></ td >< td >< code >/ buildings / { id } / rooms </ code ></ td >< td >< ? php esc_html_e ( 'List rooms in building' , 'wp-bnb' ); ?> </td></tr>
< tr >< td >< span class = " wp-bnb-method get " > GET </ span ></ td >< td >< code >/ rooms </ code ></ td >< td >< ? php esc_html_e ( 'List/search rooms' , 'wp-bnb' ); ?> </td></tr>
< tr >< td >< span class = " wp-bnb-method get " > GET </ span ></ td >< td >< code >/ rooms / { id } </ code ></ td >< td >< ? php esc_html_e ( 'Get room details' , 'wp-bnb' ); ?> </td></tr>
< tr >< td >< span class = " wp-bnb-method get " > GET </ span ></ td >< td >< code >/ rooms / { id } / availability </ code ></ td >< td >< ? php esc_html_e ( 'Check room availability' , 'wp-bnb' ); ?> </td></tr>
< tr >< td >< span class = " wp-bnb-method get " > GET </ span ></ td >< td >< code >/ rooms / { id } / calendar </ code ></ td >< td >< ? php esc_html_e ( 'Get room calendar' , 'wp-bnb' ); ?> </td></tr>
< tr >< td >< span class = " wp-bnb-method post " > POST </ span ></ td >< td >< code >/ availability / search </ code ></ td >< td >< ? php esc_html_e ( 'Search available rooms' , 'wp-bnb' ); ?> </td></tr>
< tr >< td >< span class = " wp-bnb-method get " > GET </ span ></ td >< td >< code >/ services </ code ></ td >< td >< ? php esc_html_e ( 'List services' , 'wp-bnb' ); ?> </td></tr>
< tr >< td >< span class = " wp-bnb-method post " > POST </ span ></ td >< td >< code >/ pricing / calculate </ code ></ td >< td >< ? php esc_html_e ( 'Calculate booking price' , 'wp-bnb' ); ?> </td></tr>
< tr >< td >< span class = " wp-bnb-method post " > POST </ span ></ td >< td >< code >/ bookings </ code ></ td >< td >< ? php esc_html_e ( 'Create booking (pending status)' , 'wp-bnb' ); ?> </td></tr>
</ tbody >
</ table >
< h3 >< ? php esc_html_e ( 'Admin Endpoints' , 'wp-bnb' ); ?> </h3>
< p class = " description " >< ? php esc_html_e ( 'These endpoints require authentication (Application Password or Cookie + Nonce).' , 'wp-bnb' ); ?> </p>
< table class = " widefat striped " style = " margin-bottom: 20px; " >
< thead >
< tr >
< th style = " width: 80px; " >< ? php esc_html_e ( 'Method' , 'wp-bnb' ); ?> </th>
< th style = " width: 250px; " >< ? php esc_html_e ( 'Endpoint' , 'wp-bnb' ); ?> </th>
< th >< ? php esc_html_e ( 'Description' , 'wp-bnb' ); ?> </th>
</ tr >
</ thead >
< tbody >
< tr >< td >< span class = " wp-bnb-method get " > GET </ span ></ td >< td >< code >/ bookings </ code ></ td >< td >< ? php esc_html_e ( 'List all bookings' , 'wp-bnb' ); ?> </td></tr>
< tr >< td >< span class = " wp-bnb-method get " > GET </ span ></ td >< td >< code >/ bookings / { id } </ code ></ td >< td >< ? php esc_html_e ( 'Get booking details' , 'wp-bnb' ); ?> </td></tr>
< tr >< td >< span class = " wp-bnb-method patch " > PATCH </ span ></ td >< td >< code >/ bookings / { id } </ code ></ td >< td >< ? php esc_html_e ( 'Update booking' , 'wp-bnb' ); ?> </td></tr>
< tr >< td >< span class = " wp-bnb-method delete " > DELETE </ span ></ td >< td >< code >/ bookings / { id } </ code ></ td >< td >< ? php esc_html_e ( 'Cancel booking' , 'wp-bnb' ); ?> </td></tr>
< tr >< td >< span class = " wp-bnb-method post " > POST </ span ></ td >< td >< code >/ bookings / { id } / confirm </ code ></ td >< td >< ? php esc_html_e ( 'Confirm booking' , 'wp-bnb' ); ?> </td></tr>
< tr >< td >< span class = " wp-bnb-method post " > POST </ span ></ td >< td >< code >/ bookings / { id } / check - in </ code ></ td >< td >< ? php esc_html_e ( 'Check in guest' , 'wp-bnb' ); ?> </td></tr>
< tr >< td >< span class = " wp-bnb-method post " > POST </ span ></ td >< td >< code >/ bookings / { id } / check - out </ code ></ td >< td >< ? php esc_html_e ( 'Check out guest' , 'wp-bnb' ); ?> </td></tr>
< tr >< td >< span class = " wp-bnb-method get " > GET </ span ></ td >< td >< code >/ guests </ code ></ td >< td >< ? php esc_html_e ( 'List guests' , 'wp-bnb' ); ?> </td></tr>
< tr >< td >< span class = " wp-bnb-method get " > GET </ span ></ td >< td >< code >/ guests / { id } </ code ></ td >< td >< ? php esc_html_e ( 'Get guest details' , 'wp-bnb' ); ?> </td></tr>
< tr >< td >< span class = " wp-bnb-method get " > GET </ span ></ td >< td >< code >/ guests / search </ code ></ td >< td >< ? php esc_html_e ( 'Search guests' , 'wp-bnb' ); ?> </td></tr>
</ tbody >
</ table >
< h2 style = " margin-top: 30px; " >< ? php esc_html_e ( 'Authentication' , 'wp-bnb' ); ?> </h2>
< p >< ? php esc_html_e ( 'Admin endpoints require authentication. Use one of the following methods:' , 'wp-bnb' ); ?> </p>
< table class = " form-table " >
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
< tr >
2026-02-03 21:50:12 +01:00
< th scope = " row " >
< span class = " dashicons dashicons-admin-network " style = " color: #2271b1; " ></ span >
< ? php esc_html_e ( 'Application Passwords' , 'wp-bnb' ); ?>
</ th >
< td >
< p >< ? php esc_html_e ( 'Create an Application Password in Users > Your Profile.' , 'wp-bnb' ); ?> </p>
< p >< code > Authorization : Basic base64 ( username : app - password ) </ code ></ p >
< p class = " description " >< ? php esc_html_e ( 'Recommended for external applications and integrations.' , 'wp-bnb' ); ?> </p>
</ td >
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
</ tr >
2026-02-03 21:50:12 +01:00
< tr >
< th scope = " row " >
< span class = " dashicons dashicons-lock " style = " color: #2271b1; " ></ span >
< ? php esc_html_e ( 'Cookie + Nonce' , 'wp-bnb' ); ?>
</ th >
< td >
< p >< ? php esc_html_e ( 'For same-domain JavaScript requests when user is logged in.' , 'wp-bnb' ); ?> </p>
< p >< code > X - WP - Nonce : < ? php echo esc_html ( wp_create_nonce ( 'wp_rest' ) ); ?> </code></p>
< p class = " description " >< ? php esc_html_e ( 'Best for frontend JavaScript that interacts with the API.' , 'wp-bnb' ); ?> </p>
</ td >
</ tr >
</ table >
< ? php endif ; ?>
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
</ form >
< ? php
}
2026-01-31 13:15:13 +01:00
/**
* Render license status badge .
*
* @ param string $status License status .
* @ return void
*/
private function render_license_status_badge ( string $status ) : void {
$badges = array (
'valid' => array (
'class' => 'dashicons-yes-alt' ,
'color' => '#00a32a' ,
'label' => __ ( 'Valid' , 'wp-bnb' ),
),
'invalid' => array (
'class' => 'dashicons-dismiss' ,
'color' => '#d63638' ,
'label' => __ ( 'Invalid' , 'wp-bnb' ),
),
'expired' => array (
'class' => 'dashicons-warning' ,
'color' => '#dba617' ,
'label' => __ ( 'Expired' , 'wp-bnb' ),
),
'revoked' => array (
'class' => 'dashicons-dismiss' ,
'color' => '#d63638' ,
'label' => __ ( 'Revoked' , 'wp-bnb' ),
),
'inactive' => array (
'class' => 'dashicons-marker' ,
'color' => '#72aee6' ,
'label' => __ ( 'Inactive' , 'wp-bnb' ),
),
'unchecked' => array (
'class' => 'dashicons-info' ,
'color' => '#72aee6' ,
'label' => __ ( 'Not checked' , 'wp-bnb' ),
),
'unconfigured' => array (
'class' => 'dashicons-admin-generic' ,
'color' => '#646970' ,
'label' => __ ( 'Not configured' , 'wp-bnb' ),
),
);
$badge = $badges [ $status ] ? ? $badges [ 'unconfigured' ];
?>
< span class = " wp-bnb-license-status " style = " color: <?php echo esc_attr( $badge['color'] ); ?>; " >
< span class = " dashicons <?php echo esc_attr( $badge['class'] ); ?> " ></ span >
< ? php echo esc_html ( $badge [ 'label' ] ); ?>
</ span >
< ? php
}
/**
* Save settings based on active tab .
*
* @ param string $tab Active tab .
* @ return void
*/
private function save_settings ( string $tab ) : void {
switch ( $tab ) {
2026-01-31 14:10:30 +01:00
case 'pricing' :
$this -> save_pricing_settings ();
break ;
2026-01-31 13:15:13 +01:00
case 'license' :
$this -> save_license_settings ();
break ;
2026-02-03 15:18:27 +01:00
case 'updates' :
$this -> save_updates_settings ();
break ;
2026-02-03 20:40:54 +01:00
case 'metrics' :
$this -> save_metrics_settings ();
break ;
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
case 'api' :
$this -> save_api_settings ();
break ;
Add WooCommerce integration for payments, invoices, and order management (v0.11.0)
- Product sync: Virtual WC products for rooms with bidirectional linking
- Cart/Checkout: Booking data in cart items, availability validation, dynamic pricing
- Orders: Automatic booking creation on payment, status mapping, guest record creation
- Invoices: PDF generation via mPDF, auto-attach to emails, configurable numbering
- Refunds: Full refund cancels booking, partial refund records amount only
- Admin: Cross-linked columns and row actions between bookings and orders
- Settings: WooCommerce tab with subtabs (General, Products, Orders, Invoices)
- HPOS compatibility declared for High-Performance Order Storage
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 22:40:36 +01:00
case 'woocommerce' :
$this -> save_woocommerce_settings ();
break ;
2026-01-31 13:15:13 +01:00
default :
$this -> save_general_settings ();
break ;
}
}
/**
* Save general settings .
*
* @ return void
*/
private function save_general_settings () : void {
2026-02-03 15:18:27 +01:00
// Business Information.
2026-01-31 13:15:13 +01:00
if ( isset ( $_POST [ 'wp_bnb_business_name' ] ) ) {
update_option ( 'wp_bnb_business_name' , sanitize_text_field ( wp_unslash ( $_POST [ 'wp_bnb_business_name' ] ) ) );
}
if ( isset ( $_POST [ 'wp_bnb_currency' ] ) ) {
update_option ( 'wp_bnb_currency' , sanitize_text_field ( wp_unslash ( $_POST [ 'wp_bnb_currency' ] ) ) );
}
2026-02-03 15:18:27 +01:00
// Address fields.
$address_fields = array ( 'street' , 'city' , 'postal' , 'country' );
foreach ( $address_fields as $field ) {
$key = 'wp_bnb_address_' . $field ;
if ( isset ( $_POST [ $key ] ) ) {
update_option ( $key , sanitize_text_field ( wp_unslash ( $_POST [ $key ] ) ) );
}
}
// Contact fields.
if ( isset ( $_POST [ 'wp_bnb_contact_email' ] ) ) {
update_option ( 'wp_bnb_contact_email' , sanitize_email ( wp_unslash ( $_POST [ 'wp_bnb_contact_email' ] ) ) );
}
if ( isset ( $_POST [ 'wp_bnb_contact_phone' ] ) ) {
update_option ( 'wp_bnb_contact_phone' , sanitize_text_field ( wp_unslash ( $_POST [ 'wp_bnb_contact_phone' ] ) ) );
}
if ( isset ( $_POST [ 'wp_bnb_contact_website' ] ) ) {
update_option ( 'wp_bnb_contact_website' , esc_url_raw ( wp_unslash ( $_POST [ 'wp_bnb_contact_website' ] ) ) );
}
// Social media fields.
$social_fields = array ( 'facebook' , 'instagram' , 'x' , 'linkedin' , 'tripadvisor' );
foreach ( $social_fields as $field ) {
$key = 'wp_bnb_social_' . $field ;
if ( isset ( $_POST [ $key ] ) ) {
update_option ( $key , esc_url_raw ( wp_unslash ( $_POST [ $key ] ) ) );
}
}
2026-01-31 13:15:13 +01:00
add_settings_error ( 'wp_bnb_settings' , 'settings_saved' , __ ( 'Settings saved.' , 'wp-bnb' ), 'success' );
settings_errors ( 'wp_bnb_settings' );
}
2026-01-31 14:10:30 +01:00
/**
* Save pricing settings .
*
* @ return void
*/
private function save_pricing_settings () : void {
if ( isset ( $_POST [ 'wp_bnb_short_term_max_nights' ] ) ) {
$value = absint ( $_POST [ 'wp_bnb_short_term_max_nights' ] );
$value = max ( 1 , min ( 30 , $value ) );
update_option ( 'wp_bnb_short_term_max_nights' , $value );
}
if ( isset ( $_POST [ 'wp_bnb_mid_term_max_nights' ] ) ) {
$value = absint ( $_POST [ 'wp_bnb_mid_term_max_nights' ] );
$value = max ( 7 , min ( 90 , $value ) );
update_option ( 'wp_bnb_mid_term_max_nights' , $value );
}
if ( isset ( $_POST [ 'wp_bnb_weekend_days' ] ) && is_array ( $_POST [ 'wp_bnb_weekend_days' ] ) ) {
$days = array_map ( 'absint' , $_POST [ 'wp_bnb_weekend_days' ] );
$days = array_filter ( $days , fn ( $d ) => $d >= 1 && $d <= 7 );
update_option ( 'wp_bnb_weekend_days' , implode ( ',' , $days ) );
} else {
update_option ( 'wp_bnb_weekend_days' , '' );
}
add_settings_error ( 'wp_bnb_settings' , 'settings_saved' , __ ( 'Pricing settings saved.' , 'wp-bnb' ), 'success' );
settings_errors ( 'wp_bnb_settings' );
}
2026-01-31 13:15:13 +01:00
/**
* Save license settings .
*
* @ return void
*/
private function save_license_settings () : void {
$data = array (
'license_key' => isset ( $_POST [ 'wp_bnb_license_key' ] ) ? sanitize_text_field ( wp_unslash ( $_POST [ 'wp_bnb_license_key' ] ) ) : '' ,
'server_url' => isset ( $_POST [ 'wp_bnb_license_server_url' ] ) ? esc_url_raw ( wp_unslash ( $_POST [ 'wp_bnb_license_server_url' ] ) ) : '' ,
'server_secret' => isset ( $_POST [ 'wp_bnb_license_server_secret' ] ) ? sanitize_text_field ( wp_unslash ( $_POST [ 'wp_bnb_license_server_secret' ] ) ) : '' ,
);
LicenseManager :: save_settings ( $data );
add_settings_error ( 'wp_bnb_settings' , 'settings_saved' , __ ( 'License settings saved.' , 'wp-bnb' ), 'success' );
settings_errors ( 'wp_bnb_settings' );
}
2026-02-03 15:18:27 +01:00
/**
* Save updates settings .
*
* @ return void
*/
private function save_updates_settings () : void {
$notifications_enabled = isset ( $_POST [ 'wp_bnb_update_notifications_enabled' ] ) ? 'yes' : 'no' ;
update_option ( LicenseUpdater :: OPTION_NOTIFICATIONS_ENABLED , $notifications_enabled );
$auto_install_enabled = isset ( $_POST [ 'wp_bnb_auto_install_enabled' ] ) ? 'yes' : 'no' ;
update_option ( LicenseUpdater :: OPTION_AUTO_INSTALL_ENABLED , $auto_install_enabled );
if ( isset ( $_POST [ 'wp_bnb_update_check_frequency' ] ) ) {
$frequency = absint ( $_POST [ 'wp_bnb_update_check_frequency' ] );
$frequency = max ( 1 , min ( 168 , $frequency ) ); // Clamp between 1-168 hours.
update_option ( LicenseUpdater :: OPTION_CHECK_FREQUENCY , $frequency );
// Clear update cache when frequency changes so new frequency takes effect.
$updater = LicenseUpdater :: get_instance ();
if ( null !== $updater ) {
$updater -> clear_cache ();
}
}
add_settings_error ( 'wp_bnb_settings' , 'settings_saved' , __ ( 'Update settings saved.' , 'wp-bnb' ), 'success' );
settings_errors ( 'wp_bnb_settings' );
}
2026-02-03 20:40:54 +01:00
/**
* Save metrics settings .
*
* @ return void
*/
private function save_metrics_settings () : void {
$metrics_enabled = isset ( $_POST [ 'wp_bnb_metrics_enabled' ] ) ? 'yes' : 'no' ;
update_option ( Prometheus :: OPTION_ENABLED , $metrics_enabled );
add_settings_error ( 'wp_bnb_settings' , 'settings_saved' , __ ( 'Metrics settings saved.' , 'wp-bnb' ), 'success' );
settings_errors ( 'wp_bnb_settings' );
}
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
/**
* Save API settings .
*
* @ return void
*/
private function save_api_settings () : void {
$api_enabled = isset ( $_POST [ 'wp_bnb_api_enabled' ] ) ? 'yes' : 'no' ;
$rate_limiting = isset ( $_POST [ 'wp_bnb_api_rate_limiting' ] ) ? 'yes' : 'no' ;
update_option ( 'wp_bnb_api_enabled' , $api_enabled );
update_option ( 'wp_bnb_api_rate_limiting' , $rate_limiting );
2026-02-03 21:50:12 +01:00
// Save rate limit configuration.
$defaults = \Magdev\WpBnb\Api\RateLimiter :: get_default_limits ();
$limit_window = isset ( $_POST [ 'wp_bnb_rate_limit_window' ] )
? max ( 10 , min ( 300 , absint ( $_POST [ 'wp_bnb_rate_limit_window' ] ) ) )
: 60 ;
$limit_public = isset ( $_POST [ 'wp_bnb_rate_limit_public' ] )
? max ( 1 , min ( 1000 , absint ( $_POST [ 'wp_bnb_rate_limit_public' ] ) ) )
: $defaults [ 'public' ];
$limit_avail = isset ( $_POST [ 'wp_bnb_rate_limit_availability' ] )
? max ( 1 , min ( 1000 , absint ( $_POST [ 'wp_bnb_rate_limit_availability' ] ) ) )
: $defaults [ 'availability' ];
$limit_booking = isset ( $_POST [ 'wp_bnb_rate_limit_booking' ] )
? max ( 1 , min ( 100 , absint ( $_POST [ 'wp_bnb_rate_limit_booking' ] ) ) )
: $defaults [ 'booking' ];
$limit_admin = isset ( $_POST [ 'wp_bnb_rate_limit_admin' ] )
? max ( 1 , min ( 1000 , absint ( $_POST [ 'wp_bnb_rate_limit_admin' ] ) ) )
: $defaults [ 'admin' ];
update_option ( 'wp_bnb_rate_limit_window' , $limit_window );
update_option ( 'wp_bnb_rate_limit_public' , $limit_public );
update_option ( 'wp_bnb_rate_limit_availability' , $limit_avail );
update_option ( 'wp_bnb_rate_limit_booking' , $limit_booking );
update_option ( 'wp_bnb_rate_limit_admin' , $limit_admin );
Implement Phase 10: REST API Endpoints (v0.10.0)
- Add complete REST API infrastructure under src/Api/
- ResponseFormatter for standardized responses
- RateLimiter with tiered limits (public 60/min, availability 30/min, booking 10/min, admin 120/min)
- AbstractController base class with common functionality
- BuildingsController: list, get, rooms endpoints
- RoomsController: list, get, availability, calendar, search endpoints
- BookingsController: CRUD + confirm/check-in/check-out status transitions
- GuestsController: list, get, search, booking history (admin only)
- ServicesController: list, get, calculate endpoints
- PricingController: calculate, seasons endpoints
- API settings tab with enable/disable toggles
- Comprehensive API documentation in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:24:40 +01:00
add_settings_error ( 'wp_bnb_settings' , 'settings_saved' , __ ( 'API settings saved.' , 'wp-bnb' ), 'success' );
settings_errors ( 'wp_bnb_settings' );
}
Add WooCommerce integration for payments, invoices, and order management (v0.11.0)
- Product sync: Virtual WC products for rooms with bidirectional linking
- Cart/Checkout: Booking data in cart items, availability validation, dynamic pricing
- Orders: Automatic booking creation on payment, status mapping, guest record creation
- Invoices: PDF generation via mPDF, auto-attach to emails, configurable numbering
- Refunds: Full refund cancels booking, partial refund records amount only
- Admin: Cross-linked columns and row actions between bookings and orders
- Settings: WooCommerce tab with subtabs (General, Products, Orders, Invoices)
- HPOS compatibility declared for High-Performance Order Storage
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 22:40:36 +01:00
/**
* Render WooCommerce settings tab .
*
* @ return void
*/
private function render_woocommerce_settings () : void {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Subtab switching only.
$active_subtab = isset ( $_GET [ 'subtab' ] ) ? sanitize_key ( $_GET [ 'subtab' ] ) : 'general' ;
$base_url = admin_url ( 'admin.php?page=wp-bnb-settings&tab=woocommerce' );
$wc_active = class_exists ( 'WooCommerce' );
?>
< div class = " wp-bnb-subtabs " >
< a href = " <?php echo esc_url( $base_url . '&subtab=general' ); ?> "
class = " wp-bnb-subtab <?php echo 'general' === $active_subtab ? 'active' : ''; ?> " >
< span class = " dashicons dashicons-admin-generic " ></ span >
< ? php esc_html_e ( 'General' , 'wp-bnb' ); ?>
</ a >
< a href = " <?php echo esc_url( $base_url . '&subtab=products' ); ?> "
class = " wp-bnb-subtab <?php echo 'products' === $active_subtab ? 'active' : ''; ?> " >
< span class = " dashicons dashicons-products " ></ span >
< ? php esc_html_e ( 'Products' , 'wp-bnb' ); ?>
</ a >
< a href = " <?php echo esc_url( $base_url . '&subtab=orders' ); ?> "
class = " wp-bnb-subtab <?php echo 'orders' === $active_subtab ? 'active' : ''; ?> " >
< span class = " dashicons dashicons-cart " ></ span >
< ? php esc_html_e ( 'Orders' , 'wp-bnb' ); ?>
</ a >
< a href = " <?php echo esc_url( $base_url . '&subtab=invoices' ); ?> "
class = " wp-bnb-subtab <?php echo 'invoices' === $active_subtab ? 'active' : ''; ?> " >
< span class = " dashicons dashicons-media-document " ></ span >
< ? php esc_html_e ( 'Invoices' , 'wp-bnb' ); ?>
</ a >
</ div >
< ? php if ( ! $wc_active ) : ?>
< div class = " notice notice-warning inline " >
< p >
< strong >< ? php esc_html_e ( 'WooCommerce is not active.' , 'wp-bnb' ); ?> </strong>
< ? php esc_html_e ( 'Please install and activate WooCommerce to use these features.' , 'wp-bnb' ); ?>
</ p >
</ div >
< ? php endif ; ?>
< ? php
switch ( $active_subtab ) {
case 'products' :
$this -> render_wc_products_subtab ( $wc_active );
break ;
case 'orders' :
$this -> render_wc_orders_subtab ( $wc_active );
break ;
case 'invoices' :
$this -> render_wc_invoices_subtab ( $wc_active );
break ;
default :
$this -> render_wc_general_subtab ( $wc_active );
break ;
}
}
/**
* Render WooCommerce General subtab .
*
* @ param bool $wc_active Whether WooCommerce is active .
* @ return void
*/
private function render_wc_general_subtab ( bool $wc_active ) : void {
?>
< form method = " post " action = " " >
< ? php wp_nonce_field ( 'wp_bnb_save_settings' , 'wp_bnb_settings_nonce' ); ?>
< input type = " hidden " name = " wc_subtab " value = " general " >
< h2 >< ? php esc_html_e ( 'WooCommerce Integration' , 'wp-bnb' ); ?> </h2>
< table class = " form-table " role = " presentation " >
< tr >
< th scope = " row " >< ? php esc_html_e ( 'Enable Integration' , 'wp-bnb' ); ?> </th>
< td >
< label for = " wp_bnb_wc_enabled " >
< input type = " checkbox " name = " wp_bnb_wc_enabled " id = " wp_bnb_wc_enabled " value = " yes "
< ? php checked ( 'yes' , get_option ( WooCommerceManager :: OPTION_ENABLED , 'no' ) ); ?>
< ? php disabled ( ! $wc_active ); ?> >
< ? php esc_html_e ( 'Enable WooCommerce integration for bookings' , 'wp-bnb' ); ?>
</ label >
< p class = " description " >
< ? php esc_html_e ( 'Allow guests to book and pay through WooCommerce checkout.' , 'wp-bnb' ); ?>
</ p >
</ td >
</ tr >
< tr >
< th scope = " row " >< ? php esc_html_e ( 'Auto-Confirm Bookings' , 'wp-bnb' ); ?> </th>
< td >
< label for = " wp_bnb_wc_auto_confirm_booking " >
< input type = " checkbox " name = " wp_bnb_wc_auto_confirm_booking " id = " wp_bnb_wc_auto_confirm_booking " value = " yes "
< ? php checked ( 'yes' , get_option ( WooCommerceManager :: OPTION_AUTO_CONFIRM , 'yes' ) ); ?>
< ? php disabled ( ! $wc_active ); ?> >
< ? php esc_html_e ( 'Automatically confirm booking when payment is completed' , 'wp-bnb' ); ?>
</ label >
< p class = " description " >
< ? php esc_html_e ( 'If disabled, bookings will remain pending until manually confirmed.' , 'wp-bnb' ); ?>
</ p >
</ td >
</ tr >
</ table >
< ? php if ( $wc_active ) : ?>
< p class = " submit " >
< input type = " submit " name = " submit " class = " button button-primary "
value = " <?php esc_attr_e( 'Save Settings', 'wp-bnb' ); ?> " >
</ p >
< ? php endif ; ?>
</ form >
< ? php
}
/**
* Render WooCommerce Products subtab .
*
* @ param bool $wc_active Whether WooCommerce is active .
* @ return void
*/
private function render_wc_products_subtab ( bool $wc_active ) : void {
$categories = array ();
if ( $wc_active ) {
$categories = get_terms (
array (
'taxonomy' => 'product_cat' ,
'hide_empty' => false ,
)
);
}
?>
< form method = " post " action = " " >
< ? php wp_nonce_field ( 'wp_bnb_save_settings' , 'wp_bnb_settings_nonce' ); ?>
< input type = " hidden " name = " wc_subtab " value = " products " >
< h2 >< ? php esc_html_e ( 'Product Synchronization' , 'wp-bnb' ); ?> </h2>
< table class = " form-table " role = " presentation " >
< tr >
< th scope = " row " >< ? php esc_html_e ( 'Auto-Sync Products' , 'wp-bnb' ); ?> </th>
< td >
< label for = " wp_bnb_wc_auto_sync_products " >
< input type = " checkbox " name = " wp_bnb_wc_auto_sync_products " id = " wp_bnb_wc_auto_sync_products " value = " yes "
< ? php checked ( 'yes' , get_option ( WooCommerceManager :: OPTION_AUTO_SYNC , 'yes' ) ); ?>
< ? php disabled ( ! $wc_active ); ?> >
< ? php esc_html_e ( 'Automatically create/update WooCommerce products when rooms are saved' , 'wp-bnb' ); ?>
</ label >
</ td >
</ tr >
< tr >
< th scope = " row " >
< label for = " wp_bnb_wc_product_category " >< ? php esc_html_e ( 'Product Category' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< select name = " wp_bnb_wc_product_category " id = " wp_bnb_wc_product_category " < ? php disabled ( ! $wc_active ); ?> >
< option value = " " >< ? php esc_html_e ( '— No category —' , 'wp-bnb' ); ?> </option>
< ? php foreach ( $categories as $cat ) : ?>
< option value = " <?php echo esc_attr( $cat->term_id ); ?> "
< ? php selected ( get_option ( WooCommerceManager :: OPTION_PRODUCT_CATEGORY , 0 ), $cat -> term_id ); ?> >
< ? php echo esc_html ( $cat -> name ); ?>
</ option >
< ? php endforeach ; ?>
</ select >
< p class = " description " >
< ? php esc_html_e ( 'Assign synced room products to this WooCommerce category.' , 'wp-bnb' ); ?>
</ p >
</ td >
</ tr >
</ table >
< ? php if ( $wc_active ) : ?>
< h3 >< ? php esc_html_e ( 'Manual Sync' , 'wp-bnb' ); ?> </h3>
< p >
< button type = " button " class = " button bnb-sync-rooms-btn " >
< span class = " dashicons dashicons-update " ></ span >
< ? php esc_html_e ( 'Sync All Rooms Now' , 'wp-bnb' ); ?>
</ button >
< span class = " sync-status " ></ span >
</ p >
< p class = " description " >
< ? php esc_html_e ( 'Creates or updates WooCommerce products for all published rooms.' , 'wp-bnb' ); ?>
</ p >
< p class = " submit " >
< input type = " submit " name = " submit " class = " button button-primary "
value = " <?php esc_attr_e( 'Save Settings', 'wp-bnb' ); ?> " >
</ p >
< ? php endif ; ?>
</ form >
< ? php
}
/**
* Render WooCommerce Orders subtab .
*
* @ param bool $wc_active Whether WooCommerce is active .
* @ return void
*/
private function render_wc_orders_subtab ( bool $wc_active ) : void {
?>
< h2 >< ? php esc_html_e ( 'Order-Booking Status Mapping' , 'wp-bnb' ); ?> </h2>
< p class = " description " >
< ? php esc_html_e ( 'The following table shows how WooCommerce order statuses map to booking statuses.' , 'wp-bnb' ); ?>
</ p >
< table class = " widefat fixed striped " style = " max-width: 600px; margin-top: 15px; " >
< thead >
< tr >
< th >< ? php esc_html_e ( 'WooCommerce Status' , 'wp-bnb' ); ?> </th>
< th >< ? php esc_html_e ( 'Booking Status' , 'wp-bnb' ); ?> </th>
</ tr >
</ thead >
< tbody >
< tr >
< td >< ? php esc_html_e ( 'Pending Payment' , 'wp-bnb' ); ?> </td>
< td >< span class = " bnb-status-badge bnb-status-pending " >< ? php esc_html_e ( 'Pending' , 'wp-bnb' ); ?> </span></td>
</ tr >
< tr >
< td >< ? php esc_html_e ( 'On Hold' , 'wp-bnb' ); ?> </td>
< td >< span class = " bnb-status-badge bnb-status-pending " >< ? php esc_html_e ( 'Pending' , 'wp-bnb' ); ?> </span></td>
</ tr >
< tr >
< td >< ? php esc_html_e ( 'Processing' , 'wp-bnb' ); ?> </td>
< td >
< ? php if ( get_option ( WooCommerceManager :: OPTION_AUTO_CONFIRM , 'yes' ) === 'yes' ) : ?>
< span class = " bnb-status-badge bnb-status-confirmed " >< ? php esc_html_e ( 'Confirmed' , 'wp-bnb' ); ?> </span>
< ? php else : ?>
< span class = " bnb-status-badge bnb-status-pending " >< ? php esc_html_e ( 'Pending' , 'wp-bnb' ); ?> </span>
< ? php endif ; ?>
</ td >
</ tr >
< tr >
< td >< ? php esc_html_e ( 'Completed' , 'wp-bnb' ); ?> </td>
< td >< span class = " bnb-status-badge bnb-status-confirmed " >< ? php esc_html_e ( 'Confirmed' , 'wp-bnb' ); ?> </span></td>
</ tr >
< tr >
< td >< ? php esc_html_e ( 'Cancelled / Refunded / Failed' , 'wp-bnb' ); ?> </td>
< td >< span class = " bnb-status-badge bnb-status-cancelled " >< ? php esc_html_e ( 'Cancelled' , 'wp-bnb' ); ?> </span></td>
</ tr >
</ tbody >
</ table >
< h3 >< ? php esc_html_e ( 'Refund Handling' , 'wp-bnb' ); ?> </h3>
< ul style = " list-style: disc; margin-left: 20px; " >
< li >< ? php esc_html_e ( 'Full refunds automatically cancel the linked booking.' , 'wp-bnb' ); ?> </li>
< li >< ? php esc_html_e ( 'Partial refunds are recorded but do not cancel the booking.' , 'wp-bnb' ); ?> </li>
< li >< ? php esc_html_e ( 'Cancellation emails are sent when a booking is cancelled due to refund.' , 'wp-bnb' ); ?> </li>
</ ul >
< ? php
}
/**
* Render WooCommerce Invoices subtab .
*
* @ param bool $wc_active Whether WooCommerce is active .
* @ return void
*/
private function render_wc_invoices_subtab ( bool $wc_active ) : void {
?>
< form method = " post " action = " " >
< ? php wp_nonce_field ( 'wp_bnb_save_settings' , 'wp_bnb_settings_nonce' ); ?>
< input type = " hidden " name = " wc_subtab " value = " invoices " >
< h2 >< ? php esc_html_e ( 'Invoice Settings' , 'wp-bnb' ); ?> </h2>
< table class = " form-table " role = " presentation " >
< tr >
< th scope = " row " >< ? php esc_html_e ( 'Attach to Emails' , 'wp-bnb' ); ?> </th>
< td >
< label for = " wp_bnb_wc_invoice_attach " >
< input type = " checkbox " name = " wp_bnb_wc_invoice_attach " id = " wp_bnb_wc_invoice_attach " value = " yes "
< ? php checked ( 'yes' , get_option ( WooCommerceManager :: OPTION_INVOICE_ATTACH , 'yes' ) ); ?>
< ? php disabled ( ! $wc_active ); ?> >
< ? php esc_html_e ( 'Attach PDF invoice to order confirmation emails' , 'wp-bnb' ); ?>
</ label >
</ td >
</ tr >
< tr >
< th scope = " row " >
< label for = " wp_bnb_invoice_prefix " >< ? php esc_html_e ( 'Invoice Number Prefix' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< input type = " text " name = " wp_bnb_invoice_prefix " id = " wp_bnb_invoice_prefix "
value = " <?php echo esc_attr( get_option( WooCommerceManager::OPTION_INVOICE_PREFIX, 'INV-' ) ); ?> "
class = " regular-text " < ? php disabled ( ! $wc_active ); ?> >
< p class = " description " >
< ? php esc_html_e ( 'Prefix for invoice numbers (e.g., INV- for INV-00001).' , 'wp-bnb' ); ?>
</ p >
</ td >
</ tr >
< tr >
< th scope = " row " >
< label for = " wp_bnb_invoice_start_number " >< ? php esc_html_e ( 'Starting Number' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< input type = " number " name = " wp_bnb_invoice_start_number " id = " wp_bnb_invoice_start_number "
value = " <?php echo esc_attr( get_option( WooCommerceManager::OPTION_INVOICE_START_NUMBER, 1000 ) ); ?> "
class = " small-text " min = " 1 " < ? php disabled ( ! $wc_active ); ?> >
< p class = " description " >
< ? php esc_html_e ( 'Starting number for new invoices (only applies if no invoices generated yet).' , 'wp-bnb' ); ?>
</ p >
</ td >
</ tr >
< tr >
< th scope = " row " >
< label for = " wp_bnb_invoice_footer " >< ? php esc_html_e ( 'Footer Text' , 'wp-bnb' ); ?> </label>
</ th >
< td >
< textarea name = " wp_bnb_invoice_footer " id = " wp_bnb_invoice_footer " rows = " 3 " class = " large-text "
< ? php disabled ( ! $wc_active ); ?> ><?php echo esc_textarea( get_option( WooCommerceManager::OPTION_INVOICE_FOOTER, '' ) ); ?></textarea>
< p class = " description " >
< ? php esc_html_e ( 'Custom footer text for invoices (e.g., terms and conditions).' , 'wp-bnb' ); ?>
</ p >
</ td >
</ tr >
</ table >
< ? php if ( $wc_active ) : ?>
< p class = " submit " >
< input type = " submit " name = " submit " class = " button button-primary "
value = " <?php esc_attr_e( 'Save Settings', 'wp-bnb' ); ?> " >
</ p >
< ? php endif ; ?>
</ form >
< ? php
}
/**
* Save WooCommerce settings .
*
* @ return void
*/
private function save_woocommerce_settings () : void {
// phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified in render_settings_page.
$subtab = isset ( $_POST [ 'wc_subtab' ] ) ? sanitize_key ( $_POST [ 'wc_subtab' ] ) : 'general' ;
switch ( $subtab ) {
case 'products' :
$auto_sync = isset ( $_POST [ 'wp_bnb_wc_auto_sync_products' ] ) ? 'yes' : 'no' ;
$category = isset ( $_POST [ 'wp_bnb_wc_product_category' ] ) ? absint ( $_POST [ 'wp_bnb_wc_product_category' ] ) : 0 ;
update_option ( WooCommerceManager :: OPTION_AUTO_SYNC , $auto_sync );
update_option ( WooCommerceManager :: OPTION_PRODUCT_CATEGORY , $category );
break ;
case 'invoices' :
$attach = isset ( $_POST [ 'wp_bnb_wc_invoice_attach' ] ) ? 'yes' : 'no' ;
$prefix = isset ( $_POST [ 'wp_bnb_invoice_prefix' ] ) ? sanitize_text_field ( wp_unslash ( $_POST [ 'wp_bnb_invoice_prefix' ] ) ) : 'INV-' ;
$start_number = isset ( $_POST [ 'wp_bnb_invoice_start_number' ] ) ? absint ( $_POST [ 'wp_bnb_invoice_start_number' ] ) : 1000 ;
$footer = isset ( $_POST [ 'wp_bnb_invoice_footer' ] ) ? sanitize_textarea_field ( wp_unslash ( $_POST [ 'wp_bnb_invoice_footer' ] ) ) : '' ;
update_option ( WooCommerceManager :: OPTION_INVOICE_ATTACH , $attach );
update_option ( WooCommerceManager :: OPTION_INVOICE_PREFIX , $prefix );
update_option ( WooCommerceManager :: OPTION_INVOICE_START_NUMBER , $start_number );
update_option ( WooCommerceManager :: OPTION_INVOICE_FOOTER , $footer );
break ;
default : // general
$enabled = isset ( $_POST [ 'wp_bnb_wc_enabled' ] ) ? 'yes' : 'no' ;
$auto_confirm = isset ( $_POST [ 'wp_bnb_wc_auto_confirm_booking' ] ) ? 'yes' : 'no' ;
update_option ( WooCommerceManager :: OPTION_ENABLED , $enabled );
update_option ( WooCommerceManager :: OPTION_AUTO_CONFIRM , $auto_confirm );
break ;
}
add_settings_error ( 'wp_bnb_settings' , 'settings_saved' , __ ( 'WooCommerce settings saved.' , 'wp-bnb' ), 'success' );
settings_errors ( 'wp_bnb_settings' );
}
2026-01-31 14:37:48 +01:00
/**
* AJAX handler for checking room availability .
*
* @ return void
*/
public function ajax_check_availability () : void {
check_ajax_referer ( 'wp_bnb_admin_nonce' , 'nonce' );
if ( ! current_user_can ( 'edit_posts' ) ) {
wp_send_json_error (
array ( 'message' => __ ( 'You do not have permission to perform this action.' , 'wp-bnb' ) )
);
}
$room_id = isset ( $_POST [ 'room_id' ] ) ? absint ( $_POST [ 'room_id' ] ) : 0 ;
$check_in = isset ( $_POST [ 'check_in' ] ) ? sanitize_text_field ( wp_unslash ( $_POST [ 'check_in' ] ) ) : '' ;
$check_out = isset ( $_POST [ 'check_out' ] ) ? sanitize_text_field ( wp_unslash ( $_POST [ 'check_out' ] ) ) : '' ;
$exclude = isset ( $_POST [ 'exclude_booking' ] ) ? absint ( $_POST [ 'exclude_booking' ] ) : null ;
if ( ! $room_id || ! $check_in || ! $check_out ) {
wp_send_json_error (
array ( 'message' => __ ( 'Missing required parameters.' , 'wp-bnb' ) )
);
}
// Validate dates.
if ( strtotime ( $check_out ) <= strtotime ( $check_in ) ) {
wp_send_json_error (
array ( 'message' => __ ( 'Check-out date must be after check-in date.' , 'wp-bnb' ) )
);
}
$result = Availability :: check_availability_with_price ( $room_id , $check_in , $check_out , $exclude );
wp_send_json_success ( $result );
}
2026-01-31 14:59:43 +01:00
/**
* AJAX handler for searching guests by email .
*
* @ return void
*/
public function ajax_search_guest () : void {
check_ajax_referer ( 'wp_bnb_admin_nonce' , 'nonce' );
if ( ! current_user_can ( 'edit_posts' ) ) {
wp_send_json_error (
array ( 'message' => __ ( 'You do not have permission to perform this action.' , 'wp-bnb' ) )
);
}
$search = isset ( $_POST [ 'search' ] ) ? sanitize_text_field ( wp_unslash ( $_POST [ 'search' ] ) ) : '' ;
if ( strlen ( $search ) < 2 ) {
wp_send_json_success ( array ( 'guests' => array () ) );
}
// Search by email or name.
$guests = get_posts (
array (
'post_type' => Guest :: POST_TYPE ,
'post_status' => 'publish' ,
'posts_per_page' => 10 ,
'meta_query' => array (
'relation' => 'OR' ,
array (
'key' => '_bnb_guest_email' ,
'value' => $search ,
'compare' => 'LIKE' ,
),
array (
'key' => '_bnb_guest_first_name' ,
'value' => $search ,
'compare' => 'LIKE' ,
),
array (
'key' => '_bnb_guest_last_name' ,
'value' => $search ,
'compare' => 'LIKE' ,
),
),
)
);
$results = array ();
foreach ( $guests as $guest ) {
$status = get_post_meta ( $guest -> ID , '_bnb_guest_status' , true ) ? : 'active' ;
$results [] = array (
'id' => $guest -> ID ,
'name' => Guest :: get_full_name ( $guest -> ID ),
'email' => get_post_meta ( $guest -> ID , '_bnb_guest_email' , true ),
'phone' => get_post_meta ( $guest -> ID , '_bnb_guest_phone' , true ),
'status' => $status ,
);
}
wp_send_json_success ( array ( 'guests' => $results ) );
}
2026-01-31 13:15:13 +01:00
/**
* Get Twig environment .
*
* @ return Environment
*/
public function get_twig () : Environment {
if ( null === $this -> twig ) {
$loader = new FilesystemLoader ( WP_BNB_PATH . 'templates' );
$this -> twig = new Environment (
$loader ,
array (
'cache' => WP_DEBUG ? false : WP_BNB_PATH . 'cache/twig' ,
'debug' => WP_DEBUG ,
)
);
}
return $this -> twig ;
}
/**
* Render a Twig template .
*
* @ param string $template Template name .
* @ param array $context Template context .
* @ return string
*/
public function render ( string $template , array $context = array () ) : string {
return $this -> get_twig () -> render ( $template , $context );
}
}