- Added comprehensive session entry for REST API Endpoints phase - Documented all created API files and controllers - Listed key learnings about WordPress REST API patterns - Updated with release tags and commit references Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
52 KiB
WordPress BnB Manager
Author: Marco Graetsch Author URL: https://src.bundespruefstelle.ch/magdev Author Email: magdev3.0@gmail.com Repository URL: https://src.bundespruefstelle.ch/magdev/wp-bnb Issues URL: https://src.bundespruefstelle.ch/magdev/wp-bnb/issues
Project Overview
This plugin enables Wordpress to act as an full management system for BnB hosts. It can handle multiple buildings with multiple rooms each, the booking of the rooms and the guests data required for renting a room. It also can handle different prices for short-, mid- and longterm rentings, configurable by the owner. In future versions - but not yet - there could be an optional possibility to pay the bookings upfront employing parts of WooCommerce, especially the payment and invoicing functions. Each Booking can have multiple additional Service options with either a price tag or can be marked as included.
Features
- Full data definition for the owner of the business
- Custom Post-types for Buildings and Rooms, while Rooms must be assigned to a building.
- Multiple pricing classes for short- (days), mid- (weeks) and longterm (months) bookings.
- Fully integrated using Gutenberg-Blocks, Widgets and Shortcodes
- Integrates with CF7 for forms (more Form plugins my follow in future versions)
Frontend
- Advanced Search and filtering for rooms, taking availability into account
- Gutenberg-Blocks: Building, Room, Booking
- Sidebar Widgets: Similar Rooms, Buildings
- Shortcodes: Similar Rooms, Buildings
Administration
- Dedicated pages for management of buildings, rooms, guests and bookings
- Dashboard with relevant statistics
Key Fact: 100% AI-Generated
This project is proudly "vibe-coded" using Claude.AI - the entire codebase was created through AI assistance.
Temporary Roadmap
Note for AI Assistants: Clean this section after the specific features are done or new releases are made. Effective changes are tracked in CHANGELOG.md. Do not add completed versions here - document them in the Session History section at the end of this file.
Known Bugs
(none)
Technical Stack
- Language: PHP 8.3.x
- PHP-Standards: PSR-4
- Framework: Latest WordPress Plugin API
- E-commerce: WooCommerce 10.0+ (optional, not used yet)
- Template Engine: Twig 3.0 (via Composer)
- Wordpress Form-Plugin: CF7 (for Bookings et al)
- Wordpress Base Theme twentytwentyfive
- Frontend: Vanilla JavaScript
- Styling: Custom CSS
- Dependency Management: Composer
- Internationalization: WordPress i18n (.pot/.po/.mo files)
- Canonical Plugin Name:
wp-bnb - License Client:
magdev/wc-licensed-product-client
Security Best Practices
- All user inputs are sanitized (integers for quantities/prices)
- Nonce verification on form submissions
- Output escaping in templates (
esc_attr,esc_html,esc_js) - Direct file access prevention via
ABSPATHcheck - XSS-safe DOM construction in JavaScript (no
innerHTMLwith user data) - SQL injection prevention using
$wpdb->prepare()throughout
Translation Ready
All user-facing strings use:
__('Text to translate', 'wp-bnb')
_e('Text to translate', 'wp-bnb')
Text domain: wp-bnb
Translation Template
- Base
.potfile created:languages/wp-bnb.pot - Ready for translation to any locale
- All translatable strings properly marked with text domain
Available Translations
en_US- English (United States) [base language - .pot template]de_CH- German (Switzerland, formal)
To compile translations to .mo files for production:
for po in languages/*.po; do msgfmt -o "${po%.po}.mo" "$po"; done
Create releases
- The
vendor/directory MUST be included in releases (Dependencies required for runtime) - CRITICAL: Build
vendor/for the MINIMUM supported PHP version, not the development version- Use
composer config platform.php 8.3.0before building release packages - Run
composer update --no-dev --optimize-autoloaderto rebuild dependencies
- Use
- CRITICAL: WordPress requires plugins in a subdirectory structure
- Run zip from the
plugins/parent directory, NOT from within the plugin directory - Package must extract to
wp-bnb/subdirectory with main file atwp-bnb/wp-bnb.php - Correct command:
cd /wp-content/plugins/ && zip -r wp-bnb/releases/wp-bnb-x.x.x.zip wp-bnb ... - Wrong: Running zip from inside the plugin directory creates files at root level
- Run zip from the
- CRITICAL: Exclude symlinks explicitly - zip follows symlinks by default
- Always use
-x "wp-bnb/wp-core" -x "wp-bnb/wp-core/*" -x "wp-bnb/wp-plugins" -x "wp-bnb/wp-plugins/*"to exclude development symlinks - Otherwise the entire linked directory contents will be included in the package
- Always use
- Exclusion patterns must match the relative path structure used in zip command
- Always verify the package structure with
unzip -lbefore distribution- Check all files are prefixed with
wp-bnb/ - Verify main file is at
wp-bnb/wp-bnb.php - Check for duplicate entries (indicates multiple builds in same archive)
- Check all files are prefixed with
- Test installation on the minimum supported PHP version before final deployment
- Releases are stored in
releases/including checksums - Track release changes in a single
CHANGELOG.mdfile - Bump the version number to either bugfix release versions or on new features minor release versions
- CRITICAL: WordPress reads version from TWO places - BOTH must be updated:
- Plugin header comment
Version: x.x.x- WordPress uses THIS for admin display - PHP constant
WP_BNB_VERSION(line ~28) - Used internally by the plugin
- If only the constant is updated, WordPress will show the old version in Plugins list
- Plugin header comment
Important Git Notes:
- Default branch while development is
dev - Create releases from branch
mainafter merging branchdev - Tags should use format
vX.X.X(e.g.,v1.1.22), start with v0.0.1 - Use annotated tags (
-a) not lightweight tags - Commit messages should follow the established format with Claude Code attribution
.claude/settings.local.jsonchanges are typically local-only (stash before rebasing)
CRITICAL - Release Workflow:
On every new version, ALWAYS execute this complete workflow:
# 1. Commit changes to dev branch
git add <files>
git commit -m "Description of changes (vX.X.X)"
# 2. Merge dev to main
git checkout main
git merge dev --no-edit
# 3. Create annotated tag
git tag -a vX.X.X -m "Version X.X.X - Brief description"
# 4. Push everything to origin
git push origin dev main vX.X.X
# 5. Switch back to dev for continued development
git checkout dev
Never skip any of these steps. The release is not complete until all branches and the tag are pushed to origin.
What Gets Released
- All plugin source files
- Compiled vendor dependencies
- Translation files (.mo compiled from .po)
- Assets (CSS, JS)
- Documentation (README, CHANGELOG, etc.)
What's Excluded
- Git metadata (
.git/) - Development files (
.vscode/,.claude/,CLAUDE.md,wp-core,wp-plugins) - Logs and cache files
- Previous releases
composer.lock(butvendor/is included)
For AI Assistants:
When starting a new session on this project:
- Read this CLAUDE.md file first
- Semantic versioning follows the
MAJOR.MINOR.BUGFIXpattern - Check git log for recent changes
- Verify you're on the
devbranch before making changes - Run
composer installif vendor/ is missing - Test changes before committing
- Follow commit message format with Claude Code attribution
- Update this session history section with learnings
- Never commit backup files (
*.po~,*.bak, etc.) - checkgit statusbefore committing - Follow markdown linting rules (see below)
Always refer to this document when starting work on this project.
Markdown Linting Rules
When editing CLAUDE.md or other markdown files, follow these rules to avoid linting errors:
-
MD031 - Blank lines around fenced code blocks: Always add a blank line before and after fenced code blocks, even when they follow list items. Example of correct format:
-
Item label:
(blank line here) ```php code example ``` (blank line here)
-
-
MD056 - Table column count: Table separators must have matching column counts and proper spacing. Use consistent dash lengths that match column header widths.
-
MD009 - No trailing spaces: Remove trailing whitespace from lines
-
MD012 - No multiple consecutive blank lines: Use only single blank lines between sections
-
MD040 - Fenced code blocks should have a language specified: Always add a language identifier to code blocks (e.g.,
txt,bash,php). For shortcode examples, usetxt. -
MD032 - Lists should be surrounded by blank lines: Add a blank line before AND after list blocks, including after bold labels like
**Attributes:**. -
MD034 - Bare URLs: Wrap URLs in angle brackets (e.g.,
<https://example.com>) or use markdown link syntax[text](url). -
Author section formatting: Use a heading (
### Name) instead of bold (**Name**) for the author name to maintain consistent document structure.
Project Architecture
Directory Structure
wp-bnb/
├── wp-bnb.php # Main plugin file (entry point)
├── composer.json # Composer configuration
├── composer.lock # Dependency lock file
├── CHANGELOG.md # Version history
├── CLAUDE.md # AI assistant documentation
├── PLAN.md # Implementation roadmap
├── README.md # User documentation
├── .editorconfig # Editor configuration
├── .gitignore # Git ignore patterns
├── .gitmodules # Git submodule configuration
├── .gitea/
│ └── workflows/
│ └── release.yml # CI/CD release pipeline
├── src/ # PHP source code (PSR-4: Magdev\WpBnb)
│ ├── Plugin.php # Main plugin singleton
│ ├── Admin/ # Admin pages
│ │ ├── Calendar.php # Availability calendar page
│ │ └── Seasons.php # Seasons management page
│ ├── Blocks/ # Gutenberg blocks
│ │ └── BlockRegistrar.php # Block registration and rendering
│ ├── Booking/ # Booking system
│ │ ├── Availability.php # Availability checking
│ │ └── EmailNotifier.php # Email notifications
│ ├── Frontend/ # Frontend components
│ │ ├── Search.php # Room search and AJAX handlers
│ │ ├── Shortcodes.php # All shortcode handlers
│ │ └── Widgets/ # WordPress widgets
│ │ ├── AvailabilityCalendar.php
│ │ ├── BuildingRooms.php
│ │ └── SimilarRooms.php
│ ├── License/
│ │ └── Manager.php # License management
│ ├── PostTypes/ # Custom post types
│ │ ├── Booking.php # Booking post type
│ │ ├── Building.php # Building post type
│ │ └── Room.php # Room post type
│ ├── Pricing/ # Pricing system
│ │ ├── Calculator.php # Price calculation
│ │ ├── PricingTier.php # Pricing tier enum
│ │ └── Season.php # Seasonal pricing
│ ├── Integration/ # Third-party integrations
│ │ └── CF7.php # Contact Form 7 integration
│ └── Taxonomies/ # Custom taxonomies
│ ├── Amenity.php # Amenity taxonomy (tags)
│ └── RoomType.php # Room type taxonomy (categories)
├── lib/ # Git submodules
│ └── wc-licensed-product-client/ # License client library
├── vendor/ # Composer dependencies (auto-generated)
├── assets/
│ ├── css/
│ │ ├── admin.css # Admin styles
│ │ ├── blocks-editor.css # Gutenberg editor styles
│ │ ├── cf7-integration.css # CF7 form styles
│ │ └── frontend.css # Frontend styles (~1250 lines)
│ └── js/
│ ├── admin.js # Admin scripts
│ ├── blocks-editor.js # Gutenberg editor scripts
│ ├── cf7-integration.js # CF7 form scripts
│ └── frontend.js # Frontend scripts (~825 lines)
├── templates/ # Twig templates (future)
├── languages/ # Translation files (future)
└── releases/ # Release packages (git-ignored)
Implementation Details
Main Plugin File (wp-bnb.php)
- Plugin header with metadata
- Version constants:
WP_BNB_VERSION,WP_BNB_PATH,WP_BNB_URL - PHP 8.3+ and WordPress 6.0+ version checks
- Composer autoloader loading
- Activation/deactivation hooks
Plugin Class (src/Plugin.php)
- Singleton pattern for global access
- Twig environment initialization
- Admin menu registration (Dashboard, Settings)
- Settings page with tabs (General, License)
- Asset enqueuing (admin and frontend)
- License-gated frontend components
License Manager (src/License/Manager.php)
- Integration with
SecureLicenseClientorLicenseClient - Option storage for license key, server URL, server secret
- License validation with domain binding
- License activation with domain
- Status caching (24-hour transient)
- AJAX handlers for admin operations
- Exception handling for all license states
Frontend Restriction Logic
// In Plugin::init_components()
if ( ! is_admin() && LicenseManager::is_license_valid() ) {
$this->init_frontend(); // Load frontend components
}
Admin features always work; frontend requires valid license.
Session History
2026-01-31 - Version 0.0.1 (Initial Setup)
Completed:
- Explored existing project structure (configuration files only)
- Added git submodule for
wc-licensed-product-clientatlib/wc-licensed-product-client - Installed Composer dependencies (Twig 3.0, license client, Symfony HttpClient)
- Studied license client documentation and wp-fedistream implementation
- Created main plugin file
wp-bnb.phpwith version checks - Created
Pluginsingleton class with admin integration - Created
License\Managerwith SecureLicenseClient integration - Implemented license settings page with validation/activation buttons
- Created admin CSS and JavaScript for license management
- Created Gitea CI/CD pipeline at
.gitea/workflows/release.yml - Created
PLAN.mdwith full implementation roadmap (10 phases) - Created
README.mdwith user documentation - Created
CHANGELOG.mdfollowing Keep a Changelog format - Updated
CLAUDE.mdwith architecture details
Learnings:
- License client requires checkout of specific tag (v0.2.2) for Composer path repository
- Relative URL in
.gitmodules(../wc-licensed-product-client.git) works for Gitea hosting - wp-fedistream pattern:
LicenseManager::is_license_valid()guards frontend initialization - Settings page uses tabs with nonce-protected form submission
- AJAX handlers require
check_ajax_referer()andcurrent_user_can()checks - CI/CD workflow excludes
lib/directory but includesvendor/in releases
2026-01-31 - Version 0.1.0 (Core Data Structures)
Completed:
- Created Custom Post Type: Buildings (
bnb_building)- Address meta box with full address fields
- Contact meta box with phone, email, website
- Details meta box with rooms count, floors, year built, check-in/out times
- Custom admin columns (city, country, room count)
- Sortable columns and country dropdown
- Created Custom Post Type: Rooms (
bnb_room)- Building relationship via meta field
- Room details: number, floor, size, capacity, beds, bathrooms
- Room status with color-coded badges
- Image gallery with media library and drag-and-drop sorting
- Building filter dropdown in admin list
- Custom admin columns with building link
- Created Custom Taxonomy: Room Types (
bnb_room_type)- Hierarchical structure with parent/child support
- Base capacity and sort order meta fields
- Default terms with subtypes (Standard > Single/Double/Twin, etc.)
- Created Custom Taxonomy: Amenities (
bnb_amenity)- Non-hierarchical (tag-like) structure
- Dashicon selection for visual display
- Icon column in taxonomy list
- Default amenities: WiFi, Parking, Breakfast, etc.
- Updated Plugin class to register post types and taxonomies
- Enhanced admin assets for post type edit screens
- Added gallery JavaScript with media library integration
- Updated activation hook to register CPTs before flushing rewrites
- Updated version to 0.1.0
Learnings:
- Taxonomies must be registered before post types that use them
show_in_menu => 'wp-bnb'adds post types under the plugin's main menu- Room-building relationship uses post meta, not hierarchical post types
- Gallery implementation uses
wp.mediaframe with multiple selection - Admin assets need conditional loading based on both hook suffix and post type
- Status badges use inline styles for color coding (avoiding extra CSS complexity)
2026-01-31 - Version 0.2.0 (Pricing System)
Completed:
- Created
src/Pricing/PricingTier.phpenum class- SHORT_TERM, MID_TERM, LONG_TERM cases
- Labels, units, default thresholds
fromNights()for automatic tier detection
- Created
src/Pricing/Season.phpclass- Seasonal pricing with date ranges (MM-DD format)
- Year-spanning seasons support (e.g., Dec 20 to Jan 6)
- Price modifier (multiplier) per season
- Priority system for overlapping seasons
- CRUD operations stored in wp_options
- Default seasons: High Season, Winter Holidays, Low Season
- Created
src/Pricing/Calculator.phpclass- Price calculation with tier detection
- Seasonal modifier application
- Weekend surcharge support
- Detailed price breakdown
- Currency formatting with symbol/suffix
- Added pricing meta box to Room post type
- Base prices for each tier
- Weekend surcharge field
- Link to pricing settings
- Price column in admin list
- Added Pricing tab to settings page
- Configurable tier thresholds
- Weekend days selection (checkboxes)
- Quick view of configured seasons
- Created
src/Admin/Seasons.phpadmin page- List view with all seasons
- Add/Edit season forms
- Delete with confirmation
- Create default seasons option
- Date formatting for display
- Updated admin.css with pricing styles
- Updated admin.js with pricing interactions
- Updated Plugin.php to register Seasons admin page
- Updated version to 0.2.0
Learnings:
- PHP 8.1+ enums work well for pricing tiers with methods
- Season date ranges use MM-DD format for annual recurrence
- Year-spanning seasons require special comparison logic
- Price modifiers as multipliers are more flexible than percentages
- Calculator class separates concerns from post type class
- Weekend days stored as comma-separated string in options
2026-01-31 - Version 0.3.0 (Booking System)
Completed:
- Created
src/PostTypes/Booking.phpcustom post type- Room and guest relationship tracking
- Check-in/check-out date management with validation
- Status workflow (pending, confirmed, checked_in, checked_out, cancelled)
- Auto-generated booking references (BNB-YYYY-NNNNN)
- Four meta boxes: Room & Dates, Guest Info, Pricing, Status & Notes
- Conflict detection prevents double-booking
- Price calculation using existing Calculator class
- Admin columns with room, guest, dates, nights, price, status
- Filters by room and status
- Status badges with color coding
- Created
src/Booking/Availability.phpclass- Real-time availability checking via AJAX
- Conflict detection algorithm
- Calendar data generation for rooms and buildings
- Utility methods for upcoming bookings, today's check-ins/outs
- Created
src/Admin/Calendar.phpadmin page- Monthly calendar view with room/building filters
- Color-coded booking status display
- Month navigation (previous/next/today)
- Click-to-edit booking functionality
- Hover tooltips with booking details
- Legend for status colors
- Created
src/Booking/EmailNotifier.phpclass- Admin notification for new bookings
- Guest confirmation email on booking confirmation
- Cancellation emails to guest and admin
- HTML email templates with inline styles
- Placeholder-based template system
- Filter hooks for customizing emails
- Updated
src/Plugin.php- Registered Booking post type
- Initialized Calendar admin page
- Initialized EmailNotifier
- Added AJAX handler for availability checking
- Updated asset enqueuing for Booking screens
- Updated
assets/js/admin.js- Booking form with AJAX availability checking
- Real-time nights display
- Price calculation and display
- Status preview update
- Date validation (check-out after check-in)
- Calendar page interactivity
- Updated
assets/css/admin.css- Booking info display styles
- Availability status indicators
- Price breakdown styles
- Calendar grid and cell styles
- Legend and filter styles
- Responsive design for calendar
- Updated version to 0.3.0
Learnings:
- Booking conflicts use overlap detection:
A.check_in < B.check_out AND A.check_out > B.check_in - Excluding cancelled bookings from conflict checks allows rebooking same dates
- Guest info stored in booking meta (Phase 4 will add separate Guest CPT)
- AJAX availability check returns price calculation for immediate feedback
- Calendar displays bookings color-coded by status for quick visual overview
- HTML email templates with inline CSS for better email client compatibility
- Status transitions can trigger different email notifications via hooks
- Release workflow must always include: commit to dev → merge to main → create tag → push all to origin
- Git fast-forward merge works well when dev is ahead of main with no conflicts
Released:
- Committed:
0c601dfon dev branch - Merged to main (fast-forward)
- Tagged:
v0.3.0 - Pushed to origin: dev, main, v0.3.0
2026-01-31 - Version 0.5.0 (Additional Services)
Completed:
- Created Custom Taxonomy: Service Categories (
bnb_service_category)- Non-hierarchical (tag-like) structure
- Dashicon selection for visual display
- Sort order meta field for custom ordering
- Default categories: Food & Dining, Transportation, Wellness & Spa, Activities, Housekeeping
- Created Custom Post Type: Services (
bnb_service)- Three pricing types: Included (free), Per Booking, Per Night
- Price configuration per service
- Service status (active/inactive)
- Sort order for display ordering
- Maximum quantity setting per service
- Custom admin columns: pricing type, price, status
- Filters by status and pricing type
- Helper methods:
get_service_data(),calculate_service_price(),get_services_for_booking(),format_service_price()
- Updated Booking post type with services integration
- Added
SERVICES_META_KEYconstant for services storage - New meta box: Additional Services with checkbox selection
- Quantity input for services with max_quantity > 1
- Real-time per-service line total calculation
- Services total display
- Price breakdown now shows services cost
- Grand total (room + services) in pricing meta box
- Admin list price column shows total including services
- Helper methods:
calculate_booking_services_total(),get_booking_services()
- Added
- Updated
src/Plugin.php- Registered ServiceCategory taxonomy
- Registered Service post type
- Added Service post type to asset enqueuing
- Added i18n strings for service pricing descriptions
- Updated
assets/css/admin.css- Service status badges
- Service pricing meta box styles
- Booking services selector styles
- Service item with selected state
- Quantity inputs and line totals
- Services total summary
- Grand total display
- Updated
assets/js/admin.jsinitServicePricing(): Toggle price row based on pricing typeinitBookingServices(): Service selection with real-time price calculation- Quantity change handlers with min/max enforcement
- Automatic recalculation when booking dates change
- Updated version to 0.5.0
- Updated CHANGELOG.md with Phase 5 changes
- Updated PLAN.md to mark Phase 5 complete
Learnings:
- Service pricing calculation depends on pricing_type: included=0, per_booking=priceqty, per_night=priceqty*nights
- Services are stored as JSON array in booking meta with service_id, quantity, price, pricing_type
- Same namespace classes can reference each other directly without use statements
- Services meta box renders before pricing meta box so services total is available
- Grand total calculation happens both on save (server-side) and on change (client-side JS)
2026-02-02 - Version 0.6.0 (Frontend Features)
Completed:
- Created
src/Frontend/Search.phpclass- Room search with multiple filters: availability, capacity, room type, amenities, price range, building
- AJAX endpoints:
wp_bnb_search_rooms,wp_bnb_get_availability,wp_bnb_get_calendar,wp_bnb_calculate_price - Pagination support with configurable per_page
- Room data formatting for JSON responses with thumbnails, pricing, amenities
- Price range filtering using Calculator integration
- Availability filtering using Availability class
- Created
src/Frontend/Shortcodes.phpclass[bnb_buildings]- Buildings list/grid with layout, columns, limit, orderby options[bnb_rooms]- Rooms list/grid with building, room_type, amenities filters[bnb_room_search]- Interactive search form with results container[bnb_building id="X"]- Single building display with rooms[bnb_room id="X"]- Single room display with availability form- Grid system with 1-4 column support
- Sorting options: title, date, price, capacity
- Created
src/Frontend/Widgets/directory with three widgetsSimilarRooms.php- Shows rooms from same building/room typeBuildingRooms.php- Lists all rooms in a buildingAvailabilityCalendar.php- Mini calendar with booking status- All widgets extend
WP_Widgetwith form/update/widget methods - Auto-detection of current building/room from page context
- Created
src/Blocks/BlockRegistrar.phpclass- Five Gutenberg blocks: Building, Room, Room Search, Buildings List, Rooms List
- Server-side rendering using shortcode system
- Block editor assets (CSS/JS) enqueuing
- Block data localization with buildings, rooms, room types, amenities
render_callbackfunctions for each block type
- Created
assets/js/blocks-editor.js- Block registration using
wp.blocks.registerBlockType - InspectorControls for sidebar settings panels
- ServerSideRender for live preview in editor
- Attribute definitions matching shortcode parameters
- Block registration using
- Created
assets/css/blocks-editor.css- Minimal editor styling for block placeholders
- Preview container styling
- Updated
assets/css/frontend.css(~1250 lines)- CSS custom properties for theming (colors, spacing, border-radius)
- Building and room card components
- Search form with field groups
- Results grid with responsive columns
- Calendar widget with availability states (available, booked, past, today)
- Legend styling
- Responsive breakpoints: 480px, 768px, 1024px
- Updated
assets/js/frontend.js(~825 lines)WpBnbnamespace with utility methods (ajax, formatDate, parseDate, debounce)SearchFormclass: form submission, date validation, results rendering, load moreCalendarWidgetclass: month navigation, AJAX calendar loadingAvailabilityFormclass: availability checking on single room pagesPriceCalculatorclass: real-time price calculation with breakdown- XSS-safe DOM construction using textContent instead of innerHTML
- Updated
src/Plugin.php- Added use statements for new frontend classes
init_frontend()initializes Search, Shortcodes, BlockRegistrarregister_widgets()method for widget registrationwp_localize_script()adds AJAX URL, nonce, i18n strings to frontend
- Updated version to 0.6.0 in both plugin header and constant
- Updated CHANGELOG.md with comprehensive v0.6.0 release notes
- Updated PLAN.md to mark Phase 6 complete
Learnings:
- Server-side rendered Gutenberg blocks avoid complex build processes and ensure PHP/JS output consistency
- Shortcode system works well as render backend for blocks via
render_callback - Widget auto-detection from page context (
is_singular(),get_the_ID()) reduces configuration - CSS custom properties enable easy theming without modifying core styles
- AJAX nonce verification requires
wp_ajax_nopriv_for non-logged-in users in frontend search - Calendar data from
Availability::get_calendar_data()provides consistent format for PHP and JS rendering - XSS prevention in JS: use
textContentfor user data,createElementfor structure - Frontend components require license check (
LicenseManager::is_license_valid()) before initialization - Block editor requires separate script handle from frontend to avoid conflicts
Released:
- Committed:
864b8b2on dev branch - Merged to main (fast-forward)
- Tagged:
v0.6.0 - Pushed to origin: dev, main, v0.6.0
2026-02-03 - Bug Fixes and Enhancements
Completed:
- Fixed gap between settings page tabs and tab content
- Changed
.nav-tab-wrappermargin-bottom from 20px to 0 - Added explicit border-bottom to create seamless connection with tab content
- Changed
- Added license bypass for localhost development environments
- Created
LicenseManager::is_localhost()method - Detects: localhost, 127.0.0.1, ::1, .local/.test/.localhost/.dev/.ddev.site domains, private IP ranges
is_license_valid()now returns true for localhost environments- Added "Development Mode" notice on license settings page and dashboard when localhost detected
- Created
- Expanded General Settings with business owner fields
- Added Address section: street, city, postal code, country
- Added Contact section: email, phone, website
- Added Social Media section: Facebook, Instagram, X (Twitter), LinkedIn, TripAdvisor
- Updated
save_general_settings()with proper sanitization for all new fields
- Created subtabs on Pricing settings tab
- Three subtabs: Pricing Tiers, Weekend Days, Seasons
- Each subtab has its own save button and focused content
- Added CSS for subtab navigation styling
- Seasons subtab now shows priority column and direct link to Seasons Manager
- Implemented auto-updates system
- Created
src/License/Updater.phpclass - Integrates with WordPress plugin update system via
pre_set_site_transient_update_plugins - Provides plugin info for "View details" modal via
plugins_apifilter - Uses license client's
checkForUpdates()method - Configurable check frequency (1-168 hours)
- Options for notifications enabled and auto-install enabled
- Automatic cache clearing when license settings change or after updates
- Created
- Added Updates tab to settings page
- Enable/disable update notifications
- Enable/disable automatic updates
- Configurable update check frequency
- Manual "Check for Updates" button with AJAX
- Display of last check timestamp and current version
- Reordered admin submenu for better organization
- Dashboard at top, Settings at bottom
- Logical grouping: Buildings, Rooms, Bookings, Guests, Services, Calendar, Seasons
- Fixed Booking admin issues
- Fixed auto-draft status causing type errors (check for WP_Post object)
- Fixed guest dropdown to always load existing guests
- Booking title now auto-generates with guest name and dates (room removed per user request)
- Fixed booking history display on Guest edit page
- Implemented guest auto-creation from booking form
- When new guest data is entered in booking, guest record is automatically created
- Links booking to the new guest via guest_id meta
- Added encryption for sensitive guest data
- ID/passport numbers encrypted using AES-256-CBC
- Uses WordPress AUTH_KEY for encryption key derivation
encrypt()anddecrypt()methods in Guest class- Backward compatible with legacy unencrypted data
- Security notice displayed in Identification meta box
- Disabled Gutenberg block editor for form-based post types
- Service, Guest, and Booking post types now use classic editor
- Added
disable_block_editor()filter to each post type class - Meta boxes now appear properly instead of being hidden at bottom
- Form-based interfaces are more appropriate than block editor for data entry
Files Changed:
assets/css/admin.css- Fixed tab gap, added subtab styles, booking form stylesassets/js/admin.js- AJAX update check, booking form improvements, guest auto-creationsrc/License/Manager.php- Addedis_localhost()method, updatedis_license_valid()src/License/Updater.php- New file for auto-updates with configurable settingssrc/Plugin.php- Business owner settings, pricing subtabs, updates tab, menu reorderingsrc/PostTypes/Booking.php- Auto-draft fixes, title generation, guest creation, disable Gutenbergsrc/PostTypes/Guest.php- AES-256-CBC encryption for ID numbers, disable Gutenbergsrc/PostTypes/Service.php- Disable Gutenberg for classic editor UI
Learnings:
- WordPress nav-tab styling expects tabs and content to be flush (no margin/gap)
- Localhost detection should cover common development TLDs (.local, .test, .dev, .ddev.site)
- Private IP ranges can be detected using
FILTER_FLAG_NO_PRIV_RANGE - WordPress plugin updates require hooking into
pre_set_site_transient_update_pluginsandplugins_api - Subtabs can be implemented with query parameters and conditional rendering within a single settings callback
- URL fields should use
esc_url_raw()for sanitization, email fields usesanitize_email() - Always check if post object is valid (
$post instanceof \WP_Post) before accessing properties - auto-draft causes issues - AES-256-CBC encryption with random IV provides secure storage for sensitive data
- Store IV concatenated with encrypted data (IV is not secret, just needs to be unique)
use_block_editor_for_post_typefilter disables Gutenberg per post type- Post types with
show_in_rest => trueget Gutenberg by default, which hides traditional meta boxes - Form-based admin interfaces (data entry) should use classic editor, not block editor
2026-02-03 - Version 0.7.0 (Contact Form 7 Integration)
Completed:
- Created
src/Integration/CF7.php(~750 lines)- Custom form tags:
[bnb_building_select],[bnb_room_select],[bnb_date_checkin],[bnb_date_checkout],[bnb_guests] - Server-side validation for all custom tags
- Availability validation in
wpcf7_before_send_mailhook - Automatic booking creation on form submission via
wpcf7_mail_sent - Guest record creation/linking using
find_or_create_guest()pattern - Custom mail tags:
[_bnb_room_name],[_bnb_building_name],[_bnb_calculated_price],[_bnb_nights],[_bnb_booking_reference] - Form type detection via CSS class
wp-bnb-booking-form
- Custom form tags:
- Created
assets/js/cf7-integration.js(~230 lines)- Building-based room filtering (rooms dropdown updates when building selected)
- Date validation (check-out after check-in, no past dates)
- Guest capacity validation against room limits
- AJAX availability checking with status display
- AJAX price calculation with formatted display
- Debounced updates to prevent excessive requests
- Created
assets/css/cf7-integration.css(~200 lines)- Two-column responsive form layout
- Availability status indicators (checking spinner, available checkmark, unavailable X)
- Price display formatting
- Capacity warning styling
- Dark mode support via
prefers-color-scheme - Print styles (hide interactive elements)
- Updated
src/Plugin.php- Added
use Magdev\WpBnb\Integration\CF7import - CF7 initialization in
init_frontend()when WPCF7 class exists - CF7 assets enqueuing with localized i18n strings
- Added
- Updated
README.mdwith comprehensive CF7 documentation- Custom form tags reference with options
- Example booking form template
- Example inquiry form template
- Custom mail tags documentation
Files Created:
src/Integration/CF7.php- Main CF7 integration classassets/js/cf7-integration.js- Frontend JavaScriptassets/css/cf7-integration.css- Form styling
Learnings:
- CF7 custom tags registered via
wpcf7_add_form_tag()with callback functions - Validation filters follow pattern
wpcf7_validate_{tag_name} wpcf7_before_send_mailcan abort submission by setting$abortto true and adding validation errorwpcf7_mail_sentfires after successful email, ideal for booking creation- Custom mail tags via
wpcf7_special_mail_tagsfilter receive submission data - Form type detection by CSS class more reliable than checking for specific tags
- Room dropdown with
data-buildingattributes enables client-side filtering - AJAX endpoints reuse existing
wp_bnb_get_availabilityandwp_bnb_calculate_priceactions - CF7 assets should depend on
contact-form-7script/style handles - Guest linking uses email as unique identifier for find-or-create pattern
Released:
- Committed:
28350aaon dev branch - Merged to main (fast-forward)
- Tagged:
v0.7.0 - Pushed to origin: dev, main, v0.7.0
2026-02-03 - Version 0.7.1 (CF7 Tag Generators)
Completed:
- Added CF7 tag generator buttons for admin form editor
- Hook into
wpcf7_admin_initto register tag generators register_tag_generators()method usingWPCF7_TagGenerator::add()- BnB Building select generator with
first_as_labeloption - BnB Room select generator with
building_fieldandinclude_priceoptions - BnB Check-in date generator with
min_advanceandmax_advanceoptions - BnB Check-out date generator with
checkin_field,min_nights,max_nightsoptions - BnB Guests count generator with
room_field,min,max,defaultoptions - All generators support
idandclassattribute configuration - CF7 v2 tag generator format with
version => '2'option
- Hook into
- Removed bug from Known Bugs section in CLAUDE.md
Files Changed:
src/Integration/CF7.php- Added ~560 lines for tag generator registration and modal callbacksCLAUDE.md- Removed bug from Known Bugs sectionwp-bnb.php- Version bump to 0.7.1CHANGELOG.md- Added v0.7.1 release notes
Learnings:
- CF7 tag generators use
WPCF7_TagGenerator::get_instance()->add()for registration - Tag generator callbacks receive
$contact_formand$optionsparameters - CF7 v2 tag generator format requires
'version' => '2'in options array - Modal HTML structure:
<header class="description-box">,<div class="control-box">,<footer class="insert-box"> - Form inputs use classes like
tg-name,oneline,option,idvalue,classvaluefor CF7's JavaScript handling - The
tag-generator-insert-buttonclass triggers CF7's tag insertion JavaScript - Mail tag tip shows users which tag to use in the Mail tab
- Tag generators are registered at priority 60 in
wpcf7_admin_initto appear after core tags
Released:
- Committed:
a784d92on dev branch - Merged to main (fast-forward)
- Tagged:
v0.7.1 - Pushed to origin: dev, main, v0.7.1
2026-02-03 - Version 0.8.0 (Dashboard & Reports)
Completed:
- Created
src/Admin/Dashboard.phpclass (~700 lines)render()method for full dashboard page- Occupancy stat card with current rate, room count, comparison to last month
- Revenue stat card with this month, YTD, comparison
- Bookings stat card with pending/confirmed counts
- Guests stat card with total, new this month, repeat guests
- Today's Activity widget showing check-ins and check-outs
- Upcoming Bookings widget with next 7 days' bookings
- Quick Actions widget (New Booking, New Guest, Calendar, Reports)
- Occupancy trend chart (30-day line chart)
- Revenue trend chart (6-month bar chart)
- Data methods:
get_occupancy_stats(),get_revenue_stats(),get_booking_stats(),get_guest_stats() - Chart data methods:
get_occupancy_trend_data(),get_revenue_trend_data() - Transient caching for expensive calculations (1-hour expiry)
- Created
src/Admin/Reports.phpclass (~1100 lines)- Tabbed interface: Occupancy, Revenue, Guests
- Date range filters with presets (this month, last month, this year, custom)
- Occupancy Report: by room, by building with progress bars and status labels
- Revenue Report: by room, by pricing tier, with averages
- Guest Statistics: top guests by revenue, nationality breakdown
- CSV export using native PHP
fputcsv() - PDF export using mPDF with professional HTML styling
- Summary cards with key metrics
- Progress bar visualizations for occupancy rates
- Added mPDF dependency to
composer.json(mpdf/mpdf ^8.2) - Updated
src/Plugin.php- Added Dashboard and Reports class imports
render_dashboard_page()delegates toDashboard::render()- Added
render_reports_page()method - Reports submenu registration
- Updated menu ordering to include Reports
- Chart.js CDN enqueuing on dashboard page
- Chart data passed via
wp_localize_script()
- Dashboard CSS styles (~350 lines in admin.css)
- Responsive grid layout (4-col stats, 2-col charts, 3-col activity)
- Stat cards with icons and gradients
- Widget components with headers
- Activity list styling
- Upcoming bookings table
- Quick action buttons grid
- Reports CSS styles (~200 lines in admin.css)
- Filter form layout
- Summary cards with primary variant
- Progress bars for occupancy
- Status labels (high/medium/low)
- Export buttons styling
- JavaScript additions in admin.js
initDashboardCharts()for Chart.js initialization- Occupancy line chart with tooltips and styling
- Revenue bar chart with currency formatting
initReportsPage()for custom date toggle
- Updated version to 0.8.0
Files Created:
src/Admin/Dashboard.php- Dashboard page with widgets and chartssrc/Admin/Reports.php- Reports page with tabs and export
Files Changed:
composer.json- Added mpdf/mpdf dependencycomposer.lock- Updated with mPDF and dependenciessrc/Plugin.php- Dashboard/Reports integration, Chart.js enqueuingassets/css/admin.css- Dashboard and Reports styles (~550 lines added)assets/js/admin.js- Chart initialization, reports page handlerswp-bnb.php- Version bump to 0.8.0CHANGELOG.md- Added v0.8.0 release notesPLAN.md- Marked Phase 8 as complete
Learnings:
- Chart.js CDN loading requires conditional enqueuing to avoid loading on all admin pages
- Dashboard data methods should use transient caching for expensive queries
- PDF export with mPDF requires HTML string generation with inline CSS
- Reports use
get_posts()with meta queries for date range filtering - Progress bar visualization done with CSS positioning and
min(100, value)clamping - Chart.js 4.x uses
new Chart()constructor with configuration object - PDF generation needs
try/catchfor mPDF exceptions - CSV export with BOM (
\xEF\xBB\xBF) ensures Excel compatibility - Guest data aggregation from bookings uses unique key pattern for anonymous guests
- Occupancy calculation: (booked nights / total room nights) * 100
2026-02-03 - Version 0.9.0 (Prometheus Metrics)
Completed:
- Created
src/Integration/Prometheus.phpclass (~700 lines)- Integration with wp-prometheus via
wp_prometheus_collect_metricshook - Dashboard registration via
wp_prometheus_register_dashboardshook - Option to enable/disable metrics collection
- Inventory metrics: buildings total, rooms by status, services by status
- Booking metrics: by status, check-ins/outs today, upcoming 7 days, avg duration
- Guest metrics: total, by status, repeat guests, new this month
- Occupancy metrics: current rate, monthly rate, occupied rooms, bed capacity
- Revenue metrics: this month, YTD, avg booking value, services revenue
- Optimized SQL queries using
$wpdb->prepare()throughout
- Integration with wp-prometheus via
- Created
assets/grafana/wp-bnb-dashboard.jsonGrafana dashboard- 24 panels with responsive grid layout
- Occupancy gauges with color-coded thresholds (red < 30%, orange < 50%, yellow < 70%, green ≥ 70%)
- Pie charts for bookings, rooms, and guests by status
- Revenue stat panels (this month, YTD, avg value, services)
- Guest stat panels (total, new, repeat, active services)
- Today's activity panels (check-ins, check-outs, upcoming)
- Prometheus datasource variable for flexibility
- Auto-refresh every 5 minutes
- Updated
src/Plugin.php- Added Prometheus class import
- Initialized Prometheus integration in
init_components() - Added "Metrics" tab to settings page (6 tabs total)
- Added
render_metrics_settings()method with WP Prometheus detection - Added
save_metrics_settings()method - Metrics reference table showing all available metrics
- Updated version to 0.9.0
Files Created:
src/Integration/Prometheus.php- Prometheus metrics integration classassets/grafana/wp-bnb-dashboard.json- Pre-configured Grafana dashboard
Files Changed:
src/Plugin.php- Prometheus initialization, metrics settings tabwp-bnb.php- Version bump to 0.9.0 (header and constant)CHANGELOG.md- Added v0.9.0 release notesPLAN.md- Marked Phase 9 as completeREADME.md- Added Prometheus metrics documentation
Learnings:
- wp-prometheus uses
wp_prometheus_collect_metricsaction with collector object - Collector provides
register_gauge()for fluctuating values - Labels are passed as array to
register_gauge(), values toset() - Grafana dashboard JSON requires proper panel IDs and grid positions
- Occupancy queries need careful date range handling for month boundaries
- Revenue queries use
DECIMAL(10,2)casting for accurate sums - Metrics should be cached or computed efficiently as they're scraped frequently
- Dashboard registration requires file path, title, description, icon, and plugin name
- Settings tab detection uses
$prometheus_activeto show WP Prometheus status
2026-02-03 - Version 0.10.0/0.10.1 (REST API Endpoints)
Completed:
- Created
src/Api/RestApi.phpmain registration class- Namespace constant:
wp-bnb/v1 - Controller initialization and route registration
- Integration with Plugin class via
rest_api_inithook
- Namespace constant:
- Created
src/Api/RateLimiter.php- Transient-based rate limiting per client (user ID or IP)
- Tiered limits: public (60/min), availability (30/min), booking (10/min), admin (120/min)
- Configurable via WordPress options with fallback defaults
check(),get_retry_after(),get_rate_limit_info()methods
- Created
src/Api/ResponseFormatter.php- Standardized success/error responses
success(),collection(),created()methods- Error helpers:
validation_error(),not_found(),forbidden(),conflict(),rate_limit_error()
- Created
src/Api/Controllers/AbstractController.php- Base class extending
WP_REST_Controller - Rate limit checking and header injection
- Client IP detection (supports Cloudflare, proxies)
- Common permission callbacks:
public_permission(),admin_permission(),manage_bookings_permission() - Helper methods:
validate_date(),validate_future_date(),get_pagination_params(),get_sorting_params() - Image formatting:
format_featured_image(),format_image() - HATEOAS links via
add_links()
- Base class extending
- Created
src/Api/Controllers/BuildingsController.php- GET /buildings - List with pagination, search, orderby
- GET /buildings/{id} - Single building with address, contact, rooms count
- GET /buildings/{id}/rooms - Rooms in building
- Created
src/Api/Controllers/RoomsController.php- GET /rooms - List with filters (building, room_type, amenities, capacity, status)
- GET /rooms/{id} - Full room data with gallery, pricing, amenities
- GET /rooms/{id}/availability - Check availability using
Availability::check_availability_with_price() - GET /rooms/{id}/calendar - Monthly calendar using
Availability::get_calendar_data()
- Created
src/Api/Controllers/AvailabilityController.php- POST /availability/search - Search available rooms with date range, capacity, filters
- Created
src/Api/Controllers/BookingsController.php- POST /bookings - Create booking with guest auto-creation, conflict check
- GET /bookings - Admin list with filters (status, room, date range)
- GET /bookings/{id} - Full booking with room, guest, services
- PATCH /bookings/{id} - Update booking details
- DELETE /bookings/{id} - Cancel booking (sets status to cancelled)
- POST /bookings/{id}/confirm - Status transition
- POST /bookings/{id}/check-in - Status transition
- POST /bookings/{id}/check-out - Status transition
- Created
src/Api/Controllers/GuestsController.php- GET /guests - Admin list with search, status filter
- GET /guests/{id} - Guest data (excludes encrypted ID numbers)
- GET /guests/search - Quick search by name/email
- GET /guests/{id}/bookings - Guest's booking history
- Created
src/Api/Controllers/ServicesController.php- GET /services - List active services with categories
- GET /services/{id} - Service details with pricing info
- Created
src/Api/Controllers/PricingController.php- POST /pricing/calculate - Full price breakdown with room, dates, services
- Updated
src/Plugin.php- Added API tab to settings page with subtabs (General, Rate Limits, Endpoints)
- Enable/disable API toggle
- Configurable rate limiting with per-endpoint-type limits
- Time window configuration (10-300 seconds)
- Full endpoint documentation with HTTP method badges
- Updated
README.mdwith comprehensive REST API documentation- Endpoint reference tables (public and admin)
- Authentication examples (Application Passwords)
- Rate limiting configuration and response headers
- Code examples for common operations
Files Created:
src/Api/RestApi.php- Main API registrationsrc/Api/RateLimiter.php- Rate limitingsrc/Api/ResponseFormatter.php- Response formattingsrc/Api/Controllers/AbstractController.php- Base controllersrc/Api/Controllers/BuildingsController.php- Buildings endpointssrc/Api/Controllers/RoomsController.php- Rooms endpointssrc/Api/Controllers/AvailabilityController.php- Availability searchsrc/Api/Controllers/BookingsController.php- Bookings CRUDsrc/Api/Controllers/GuestsController.php- Guests endpointssrc/Api/Controllers/ServicesController.php- Services endpointssrc/Api/Controllers/PricingController.php- Pricing calculationMARKETING.md- Marketing texts for shops (gitignored)
Files Changed:
src/Plugin.php- API settings tab with subtabs, RestApi initializationwp-bnb.php- Version bump to 0.10.0, then 0.10.1CHANGELOG.md- Added v0.10.0 and v0.10.1 release notesPLAN.md- Marked Phase 10 as complete, reorganized roadmapREADME.md- Added REST API documentation section.gitignore- Added MARKETING.md to exclusions
Learnings:
- WordPress REST API uses
WP_REST_Controlleras base class withregister_routes()method - Route registration via
register_rest_route()with namespace, route pattern, and args - Permission callbacks return bool; use
current_user_can('edit_posts')for admin endpoints - Rate limiting with transients: store count and start time, check against limits
- Transient key should include client identifier and endpoint type hash
- X-RateLimit headers (Limit, Remaining, Reset) provide rate limit info to clients
- Application Passwords (WordPress 5.6+) recommended for external API access
- HATEOAS links added via
_linkskey in response - Conflict detection reuses existing
Availability::check_availability()method - Settings subtabs use query parameters (
subtab=general) with conditional rendering - Configurable options should have sensible defaults via
get_option($key, $default) - Marketing content (MARKETING.md) should be gitignored to keep repo focused on code
Released:
- v0.10.0: Committed
81c97c3- Base REST API implementation - v0.10.1: Committed
3f5adfb- Configurable rate limiting with settings subtabs - Tags:
v0.10.0,v0.10.1 - Pushed to origin: dev, main, both tags