Changeset 3495560
- Timestamp:
- 03/31/2026 12:46:25 PM (18 hours ago)
- Location:
- bookiflex
- Files:
-
- 18 added
- 6 deleted
- 32 edited
- 1 copied
-
tags/1.2.0 (copied) (copied from bookiflex/trunk)
-
tags/1.2.0/CHANGELOG.txt (added)
-
tags/1.2.0/assets/common/widgets/controller/index.B2RbsrGV.js (deleted)
-
tags/1.2.0/assets/common/widgets/controller/index.B3SGvgXg.js (added)
-
tags/1.2.0/assets/free/admin/index.B_cl0VpC.js (deleted)
-
tags/1.2.0/assets/free/admin/index.D9SCTotr.js (added)
-
tags/1.2.0/assets/free/admin/style.B9Y7Sqrs.css (deleted)
-
tags/1.2.0/assets/free/admin/style.CEmLATbJ.css (added)
-
tags/1.2.0/assets/manifest.json (modified) (2 diffs)
-
tags/1.2.0/assets/vendor/carbon_fields/radio-card.js (added)
-
tags/1.2.0/assets/vendor/carbon_fields/style.css (added)
-
tags/1.2.0/bookiflex.php (modified) (2 diffs)
-
tags/1.2.0/readme.txt (modified) (2 diffs)
-
tags/1.2.0/src/Admin/AssetsManager.php (modified) (1 diff)
-
tags/1.2.0/src/Admin/CPT/AccommodationType.php (modified) (3 diffs)
-
tags/1.2.0/src/Admin/CPT/CancellationPolicy.php (modified) (2 diffs)
-
tags/1.2.0/src/Admin/CPT/PaymentType.php (modified) (3 diffs)
-
tags/1.2.0/src/Admin/CPT/RatePlan.php (modified) (6 diffs)
-
tags/1.2.0/src/Core/Admin/CPT/AbstractCPT.php (modified) (1 diff)
-
tags/1.2.0/src/Core/Admin/CPT/AccommodationType.php (modified) (2 diffs)
-
tags/1.2.0/src/Core/Admin/CPT/CancellationPolicy.php (modified) (3 diffs)
-
tags/1.2.0/src/Core/Admin/CPT/PaymentType.php (modified) (1 diff)
-
tags/1.2.0/src/Core/Admin/CPT/RatePlan.php (modified) (1 diff)
-
tags/1.2.0/src/Core/Admin/Field (added)
-
tags/1.2.0/src/Core/Admin/Field/RadioCard.php (added)
-
tags/1.2.0/src/Core/Admin/Field/SectionNotice.php (added)
-
tags/1.2.0/vendor/composer/autoload_classmap.php (modified) (1 diff)
-
tags/1.2.0/vendor/composer/autoload_static.php (modified) (1 diff)
-
tags/1.2.0/vendor/composer/installed.php (modified) (2 diffs)
-
trunk/CHANGELOG.txt (added)
-
trunk/assets/common/widgets/controller/index.B2RbsrGV.js (deleted)
-
trunk/assets/common/widgets/controller/index.B3SGvgXg.js (added)
-
trunk/assets/free/admin/index.B_cl0VpC.js (deleted)
-
trunk/assets/free/admin/index.D9SCTotr.js (added)
-
trunk/assets/free/admin/style.B9Y7Sqrs.css (deleted)
-
trunk/assets/free/admin/style.CEmLATbJ.css (added)
-
trunk/assets/manifest.json (modified) (2 diffs)
-
trunk/assets/vendor/carbon_fields/radio-card.js (added)
-
trunk/assets/vendor/carbon_fields/style.css (added)
-
trunk/bookiflex.php (modified) (2 diffs)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/src/Admin/AssetsManager.php (modified) (1 diff)
-
trunk/src/Admin/CPT/AccommodationType.php (modified) (3 diffs)
-
trunk/src/Admin/CPT/CancellationPolicy.php (modified) (2 diffs)
-
trunk/src/Admin/CPT/PaymentType.php (modified) (3 diffs)
-
trunk/src/Admin/CPT/RatePlan.php (modified) (6 diffs)
-
trunk/src/Core/Admin/CPT/AbstractCPT.php (modified) (1 diff)
-
trunk/src/Core/Admin/CPT/AccommodationType.php (modified) (2 diffs)
-
trunk/src/Core/Admin/CPT/CancellationPolicy.php (modified) (3 diffs)
-
trunk/src/Core/Admin/CPT/PaymentType.php (modified) (1 diff)
-
trunk/src/Core/Admin/CPT/RatePlan.php (modified) (1 diff)
-
trunk/src/Core/Admin/Field (added)
-
trunk/src/Core/Admin/Field/RadioCard.php (added)
-
trunk/src/Core/Admin/Field/SectionNotice.php (added)
-
trunk/vendor/composer/autoload_classmap.php (modified) (1 diff)
-
trunk/vendor/composer/autoload_static.php (modified) (1 diff)
-
trunk/vendor/composer/installed.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
bookiflex/tags/1.2.0/assets/manifest.json
r3493377 r3495560 1 1 { 2 "version": "1. 1.1",3 "generated": "2026-03- 28T14:15:22.310Z",2 "version": "1.2.0", 3 "generated": "2026-03-31T12:43:23.451Z", 4 4 "external": { 5 5 "vue": "assets/vendor/vue/vue.global.prod.js", … … 15 15 }, 16 16 "admin": { 17 "js": "assets/free/admin/index. B_cl0VpC.js",18 "css": "assets/free/admin/style. B9Y7Sqrs.css"17 "js": "assets/free/admin/index.D9SCTotr.js", 18 "css": "assets/free/admin/style.CEmLATbJ.css" 19 19 }, 20 20 "widgets": { 21 21 "controller": { 22 "js": "assets/common/widgets/controller/index.B 2RbsrGV.js"22 "js": "assets/common/widgets/controller/index.B3SGvgXg.js" 23 23 }, 24 24 "booking": { -
bookiflex/tags/1.2.0/bookiflex.php
r3493377 r3495560 6 6 * Description: Direct Booking Widget for Apartments and Short-Term Rentals 7 7 * Plugin URI: https://bookiflex.com 8 * Version: 1. 1.18 * Version: 1.2.0 9 9 * Author: BookiFlex 10 10 * License: GPL-2.0-or-later … … 80 80 } 81 81 // Define plugin constants 82 define( 'BOOKIFLEX_VERSION', '1. 1.1' );82 define( 'BOOKIFLEX_VERSION', '1.2.0' ); 83 83 define( 'BOOKIFLEX_FILE', __FILE__ ); 84 84 define( 'BOOKIFLEX_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); -
bookiflex/tags/1.2.0/readme.txt
r3493377 r3495560 5 5 Tested up to: 6.9 6 6 Requires PHP: 8.1 7 Stable tag: 1. 1.17 Stable tag: 1.2.0 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 149 149 == Changelog == 150 150 151 = 1.1.1 = 152 * Fix a problem with Notifications when VAT is enabled 153 154 = 1.1.0 = 155 * Improve interface behavior (search widget) 156 * Fix minor bugs 157 158 = 1.0.2 = 159 * Fix onboarding flow 160 161 = 1.0.0 = 162 * Initial release 163 * Floating booking button and modal widget 164 * Room setup, pricing, availability, and email notifications 151 = 1.2.0 - 31 March 2026 = 152 * Improved: Redesigned admin panel for better usability and cleaner interface 153 * Improved: Added class attributes to modal trigger elements for easier customization 154 * Fixed: Offers now load correctly when clicking custom trigger elements 155 * Fixed: Admin nonce now refreshes automatically to prevent expired session errors 156 157 [See changelog for all versions](https://plugins.svn.wordpress.org/bookiflex/trunk/CHANGELOG.txt). 165 158 166 159 -
bookiflex/tags/1.2.0/src/Admin/AssetsManager.php
r3487384 r3495560 46 46 // Vue — single path, dev manifest overrides prod vue path 47 47 $this->enqueueScript( 'bookiflex-vue', $this->assetUrl( $this->asset( 'external', 'vue' ) ), ['wp-i18n'] ); 48 // Carbon fields style 49 $this->enqueueStyle( 'carbon-fields-style', $this->assetUrl( 'assets/vendor/carbon_fields/style.css' ), ['carbon-fields-metaboxes'] ); 50 // Radio card field 51 $this->enqueueScript( 52 'bookiflex-radio-card', 53 $this->assetUrl( 'assets/vendor/carbon_fields/radio-card.js' ), 54 ['carbon-fields-vendor', 'carbon-fields-core', 'carbon-fields-metaboxes'], 55 true 56 ); 48 57 $this->enqueueAdminApp(); 49 58 wp_set_script_translations( 'bookiflex-admin-app', 'bookiflex', $this->plugin->getPluginDir() . 'languages' ); -
bookiflex/tags/1.2.0/src/Admin/CPT/AccommodationType.php
r3478607 r3495560 15 15 16 16 use BookiFlex\Core\Admin\CPT\AccommodationType as BaseCPT; 17 use BookiFlex\Core\Contract\PluginInterface; 17 18 use BookiFlex\Core\Model\AccommodationType\BookingUnitTypeInterface; 18 19 use BookiFlex\Core\Util\ProFeature; … … 21 22 defined( 'ABSPATH' ) || exit; 22 23 class AccommodationType extends BaseCPT { 24 public function register( PluginInterface $plugin ) : void { 25 parent::register( $plugin ); 26 $this->customizeMenuOrder( __( 'Display order', 'bookiflex' ), __( 'Controls the display order of this rental unit on the booking widget. Lower numbers appear first.', 'bookiflex' ) ); 27 $this->customizeExcerpt( __( 'Description', 'bookiflex' ), __( 'A brief description of this unit. This text may be shown to guests during the booking process.', 'bookiflex' ) ); 28 } 29 23 30 public function registerMetaBoxes() : void { 24 31 $overviewFields = [ 25 Field::make( 'text', self::FIELD_ SHORT_CODE, __( 'Short code', 'bookiflex' ) )->set_width( 34 )->set_attribute( 'maxLength', '10' )->set_attribute( 'readOnly', 'true' )->set_attribute( 'placeholder', __( 'e.g. STD', 'bookiflex' ) )->help_text( __( 'A short identifier for this rental unit (generated automatically). For example: APT for Apartment, CAB for Cabin. This code may be used internally or in reports.', 'bookiflex' ) ),32 Field::make( 'text', self::FIELD_ADDRESS, __( 'Address', 'bookiflex' ) )->set_required()->set_help_text( __( 'The full address of the property.', 'bookiflex' ) ), 26 33 Field::make( 'text', self::FIELD_LIVING_SPACE, __( 'Living space', 'bookiflex' ) )->set_width( 33 )->set_attribute( 'placeholder', __( 'e.g. 30 m², 250 ft², 45', 'bookiflex' ) )->help_text( __( 'Specify the total living area of the rental unit (in square meters, square feet, or any unit you prefer). This information is often displayed on the unit page.', 'bookiflex' ) ), 27 34 Field::make( 'text', self::FIELD_ROOMS_COUNT, __( 'Number of rooms', 'bookiflex' ) )->set_width( 33 )->set_attribute( 'type', 'number' )->set_attribute( 'min', '1' )->set_attribute( 'placeholder', __( 'e.g. 3', 'bookiflex' ) )->help_text( __( 'Total number of separate rooms in this rental unit (bedrooms, living room, kitchen, etc.).', 'bookiflex' ) ), … … 32 39 $guestsBedFields = [Field::make( 'separator', 'bflex_main_placement_separator', __( 'Main placements', 'bookiflex' ) ), Field::make( 'select', self::FIELD_MAIN_SLEEPING_CAPACITY, __( 'Main sleeping capacity', 'bookiflex' ) )->set_width( 50 )->set_options( array_combine( range( 1, 10 ), range( 1, 10 ) ) )->set_default_value( 2 )->help_text( __( 'Enter the total number of main sleeping places (e.g., 1 double bed = 2 places).', 'bookiflex' ) ), Field::make( 'set', self::FIELD_MAIN_SLEEPING_ALLOWED_OCCUPANCY, __( 'Allowed occupancy', 'bookiflex' ) )->set_width( 50 )->set_options( array_combine( range( 1, 10 ), range( 1, 10 ) ) )->help_text( __( 'Select how many guests can stay in this accommodation. Each selected option can have its own price. <strong>Only selected occupancy options will be available for booking and pricing.</strong>', 'bookiflex' ) )]; 33 40 $guestsBedFields = array_merge( $guestsBedFields, $this->addNotice() ); 34 Container::make( 'post_meta', 'at_configuration', __( 'Configuration', 'bookiflex' ) )->where( 'post_type', '=', self::POST_TYPE )->add_tab( __( 'Overview', 'bookiflex' ), $overviewFields )->add_tab( __( 'Guests & beds', 'bookiflex' ), $guestsBedFields )->add_tab( __( 'Contact information', 'bookiflex' ), [ 35 Field::make( 'separator', 'bflex_unit_address_separator', __( 'Rental unit address', 'bookiflex' ) ), 36 Field::make( 'text', self::FIELD_ADDRESS, __( 'Address', 'bookiflex' ) )->set_required()->set_help_text( __( 'The full address of the property.', 'bookiflex' ) ), 37 Field::make( 'text', self::FIELD_LONGITUDE, __( 'Longitude', 'bookiflex' ) )->set_width( 50 )->set_help_text( __( 'Used to display the property on a map.', 'bookiflex' ) ), 38 Field::make( 'text', self::FIELD_LATITUDE, __( 'Latitude', 'bookiflex' ) )->set_width( 50 )->set_help_text( __( 'Used to display the property on a map.', 'bookiflex' ) ), 39 Field::make( 'separator', 'bflex_unit_email_separator', __( 'Email information', 'bookiflex' ) ), 41 Container::make( 'post_meta', 'at_short_code', __( 'Short code', 'bookiflex' ) )->where( 'post_type', '=', self::POST_TYPE )->set_context( 'side' )->add_fields( [Field::make( 'text', self::FIELD_SHORT_CODE, '' )->set_attribute( 'maxLength', '10' )->set_attribute( 'readOnly', 'true' )->set_attribute( 'placeholder', __( 'e.g. STD', 'bookiflex' ) )->help_text( __( 'A short identifier for this rental unit (generated automatically). For example: APT for Apartment, CAB for Cabin. This code may be used internally or in reports.', 'bookiflex' ) )] ); 42 Container::make( 'post_meta', 'at_configuration', __( 'Configuration', 'bookiflex' ) )->where( 'post_type', '=', self::POST_TYPE )->set_layout( 'tabbed-vertical' )->add_tab( __( 'Overview', 'bookiflex' ), $overviewFields )->add_tab( __( 'Guests & beds', 'bookiflex' ), $guestsBedFields )->add_tab( __( 'Email information', 'bookiflex' ), [ 40 43 Field::make( 'text', self::FIELD_PHONE, __( 'Phone Number', 'bookiflex' ) )->set_width( 50 )->set_attribute( 'type', 'tel' )->set_help_text( __( 'For guest support and communication (if not specified, the default one will be used).', 'bookiflex' ) ), 41 44 Field::make( 'text', self::FIELD_EMAIL, __( 'Email', 'bookiflex' ) )->set_width( 50 )->set_attribute( 'type', 'email' )->set_help_text( __( 'For guest support and communication (if not specified, the default one will be used).', 'bookiflex' ) ), 42 Field::make( 'textarea', self::FIELD_CHECKIN_INSTRUCTIONS, __( 'Check-in instructions', 'bookiflex' ) )->set_rows( 4 )->help_text( __( 'Important information sent to guests after booking confirmation. Include details like door codes, parking instructions, key pickup location, or check-in procedures specific to this rental unit.', 'bookiflex' ) ) 45 Field::make( 'textarea', self::FIELD_CHECKIN_INSTRUCTIONS, __( 'Check-in instructions', 'bookiflex' ) )->set_rows( 4 )->help_text( __( 'Important information sent to guests after booking confirmation. Include details like door codes, parking instructions, key pickup location, or check-in procedures specific to this rental unit.', 'bookiflex' ) ), 46 Field::make( 'separator', 'bflex_unit_address_separator', __( 'Map coordinates', 'bookiflex' ) ), 47 Field::make( 'text', self::FIELD_LONGITUDE, __( 'Longitude', 'bookiflex' ) )->set_width( 50 )->set_help_text( __( 'Used to display the property on a map.', 'bookiflex' ) ), 48 Field::make( 'text', self::FIELD_LATITUDE, __( 'Latitude', 'bookiflex' ) )->set_width( 50 )->set_help_text( __( 'Used to display the property on a map.', 'bookiflex' ) ) 43 49 ] ); 44 50 Container::make( 'post_meta', __( 'Gallery', 'bookiflex' ) )->where( 'post_type', '=', self::POST_TYPE )->add_fields( [Field::make( 'media_gallery', self::FIELD_ACCOMMODATION_GALLERY, __( 'Gallery', 'bookiflex' ) )] ); -
bookiflex/tags/1.2.0/src/Admin/CPT/CancellationPolicy.php
r3478607 r3495560 17 17 use BookiFlex\Core\Contract\CancellationPolicy\CancellationPolicyTypeInterface; 18 18 use BookiFlex\Core\Util\ProFeature; 19 use BookiFlex\Core\Admin\Field\RadioCard; 20 use BookiFlex\Core\Admin\Field\SectionNotice; 19 21 use Carbon_Fields\Container; 20 22 use Carbon_Fields\Field; … … 22 24 class CancellationPolicy extends BaseCPT { 23 25 public function registerMetaBoxes() : void { 24 // Build policy options 26 // Build policy options with descriptions for radio cards 25 27 $policyOptions = [ 26 self::RULE_FULLY_FLEXIBLE => __( 'Fully flexible', 'bookiflex' ), 27 self::RULE_STRICT => __( 'Strict', 'bookiflex' ), 28 self::RULE_FIRST_NIGHT => __( 'First night penalty', 'bookiflex' ), 29 self::RULE_NON_REFUNDABLE => __( 'Non-refundable', 'bookiflex' ), 28 self::RULE_FULLY_FLEXIBLE => [ 29 'title' => __( 'Fully flexible', 'bookiflex' ), 30 'description' => __( 'Free cancellation at any time, no penalty will be charged.', 'bookiflex' ), 31 ], 32 self::RULE_STRICT => [ 33 'title' => __( 'Strict', 'bookiflex' ), 34 'description' => __( 'Configurable cancellation with custom time window and penalty percentage.', 'bookiflex' ), 35 ], 36 self::RULE_FIRST_NIGHT => [ 37 'title' => __( 'First night penalty', 'bookiflex' ), 38 'description' => __( 'Cancellation at any time will incur a penalty equal to the first night\'s stay.', 'bookiflex' ), 39 ], 40 self::RULE_NON_REFUNDABLE => [ 41 'title' => __( 'Non-refundable', 'bookiflex' ), 42 'description' => __( 'Cancellation at any time will incur a 100% charge of the booking amount.', 'bookiflex' ), 43 ], 30 44 ]; 31 45 $fields = [ 32 Field::make( 'html', 'cancellation_policy_html' )->set_html( sprintf( '<p>%s</p>', __( 'A cancellation policy defines how and when cancellation penalties apply. Later, this policy can be assigned to a rate plan.', 'bookiflex' ) ) ), 33 Field::make( 'radio', self::FIELD_PREDEFINED_RULE, __( 'Rule', 'bookiflex' ) )->set_width( 50 )->set_help_text( __( 'Chose one of predefined policies.', 'bookiflex' ) )->set_options( $policyOptions ), 34 Field::make( 'html', self::FIELD_PREDEFINED_RULE . '_html' )->set_width( 50 )->set_html( sprintf( '<p><strong>%s</strong> - %s</p>', __( 'Fully flexible', 'bookiflex' ), __( 'Free cancellation at any time, no penalty will be charged.', 'bookiflex' ) ) . sprintf( '<p><strong>%s</strong> - %s</p>', __( 'Strict', 'bookiflex' ), __( 'Configurable cancellation with custom time window and penalty percentage.', 'bookiflex' ) ) . sprintf( '<p><strong>%s</strong> - %s</p>', __( 'First night penalty', 'bookiflex' ), __( 'Cancellation at any time will incur a penalty equal to the first night\'s stay.', 'bookiflex' ) ) . sprintf( '<p><strong>%s</strong> - %s</p>', __( 'Non-refundable', 'bookiflex' ), __( 'Cancellation at any time will incur a 100% charge of the booking amount.', 'bookiflex' ) ) ), 46 SectionNotice::make( 'cancellation_policy_html', __( 'A cancellation policy defines how and when cancellation penalties apply. Later, this policy can be assigned to a rate plan.', 'bookiflex' ) ), 47 ...RadioCard::make( 48 self::FIELD_PREDEFINED_RULE, 49 __( 'Rule', 'bookiflex' ), 50 $policyOptions, 51 self::RULE_FULLY_FLEXIBLE 52 ), 53 Field::make( 'separator', 'bflex__cp__strict_separator', __( 'Configuration', 'bookiflex' ) )->set_conditional_logic( [[ 54 'field' => self::FIELD_PREDEFINED_RULE, 55 'value' => self::RULE_STRICT, 56 ]] ), 35 57 Field::make( 'select', self::FIELD_STRICT_TIME_WINDOW, __( 'Cancellation window', 'bookiflex' ) )->set_conditional_logic( [[ 36 58 'field' => self::FIELD_PREDEFINED_RULE, -
bookiflex/tags/1.2.0/src/Admin/CPT/PaymentType.php
r3478607 r3495560 15 15 16 16 use BookiFlex\Core\Admin\CPT\PaymentType as BaseCPT; 17 use BookiFlex\Core\Admin\Field\RadioCard; 18 use BookiFlex\Core\Admin\Field\SectionNotice; 19 use BookiFlex\Core\Contract\PluginInterface; 17 20 use BookiFlex\Core\Model\PaymentType\PaymentTypeInterface; 18 21 use BookiFlex\Core\Util\ProFeature; … … 21 24 defined( 'ABSPATH' ) || exit; 22 25 class PaymentType extends BaseCPT { 26 public function register( PluginInterface $plugin ) : void { 27 parent::register( $plugin ); 28 $this->customizeExcerpt( __( 'Description', 'bookiflex' ), __( 'A brief description of this payment type. This text may be shown to guests during the booking process.', 'bookiflex' ) ); 29 } 30 23 31 public function registerMetaBoxes() : void { 24 32 $paymentGateways = $this->getPaymentGateways(); 25 33 // Build payment settings fields 26 34 $paymentSettingsFields = [ 27 Field::make( 'radio', self::FIELD_CALCULATOR_TYPE, __( 'How will the payment be collected?', 'bookiflex' ) )->set_width( 50 )->set_help_text( __( 'Choose when the booking gets confirmed. Options requiring payment will hold the booking until the guest pays within the allowed time — if not paid, the booking is canceled and availability is restored. Options without payment requirement confirm the booking immediately.', 'bookiflex' ) )->set_options( [ 28 PaymentTypeInterface::PAYMENT_ON_ARRIVAL_TYPE => __( 'Guest pays on arrival', 'bookiflex' ), 29 PaymentTypeInterface::BANK_PAYMENT_TYPE => __( 'Bank transfer (confirmed without payment)', 'bookiflex' ), 30 PaymentTypeInterface::BANK_PAYMENT_PAYABLE_TYPE => __( 'Bank transfer (payment required to confirm)', 'bookiflex' ), 31 PaymentTypeInterface::INTERNET_PAYMENT_TYPE => __( 'Guest pays online (via payment gateway)', 'bookiflex' ), 32 ] ), 35 SectionNotice::make( 'payment_type_notice', __( 'Choose when the booking gets confirmed. Options requiring payment will hold the booking until the guest pays within the allowed time — if not paid, the booking is canceled and availability is restored. Options without payment requirement confirm the booking immediately.', 'bookiflex' ) ), 36 ...RadioCard::make( 37 self::FIELD_CALCULATOR_TYPE, 38 __( 'How will the payment be collected?', 'bookiflex' ), 39 [ 40 PaymentTypeInterface::PAYMENT_ON_ARRIVAL_TYPE => [ 41 'title' => __( 'Guest pays on arrival', 'bookiflex' ), 42 'description' => __( 'Booking is confirmed immediately. No online payment required.', 'bookiflex' ), 43 ], 44 PaymentTypeInterface::BANK_PAYMENT_TYPE => [ 45 'title' => __( 'Bank transfer (no payment required)', 'bookiflex' ), 46 'description' => __( 'Booking is confirmed immediately. Bank details are shared with the guest.', 'bookiflex' ), 47 ], 48 PaymentTypeInterface::BANK_PAYMENT_PAYABLE_TYPE => [ 49 'title' => __( 'Bank transfer (payment required)', 'bookiflex' ), 50 'description' => __( 'Booking is held until the guest completes the bank transfer within the allowed time.', 'bookiflex' ), 51 ], 52 PaymentTypeInterface::INTERNET_PAYMENT_TYPE => [ 53 'title' => __( 'Online payment', 'bookiflex' ), 54 'description' => __( 'Booking is held until the guest pays online via the selected payment gateway.', 'bookiflex' ), 55 ], 56 ], 57 PaymentTypeInterface::PAYMENT_ON_ARRIVAL_TYPE 58 ), 33 59 // Payment Gateway Settings 34 60 Field::make( 'separator', 'bflex_payment_gateway_separator', __( 'Payment Gateway Settings', 'bookiflex' ) )->set_conditional_logic( [[ … … 66 92 ] ); 67 93 $paymentSettingsFields = array_merge( $paymentSettingsFields, $this->addBasePaymentSettingsFields() ); 68 Container::make( 'post_meta', __( 'Configuration', 'bookiflex' ) )->where( 'post_type', '=', self::POST_TYPE )->add_ tab( __( 'Payment Method Settings', 'bookiflex' ),$paymentSettingsFields );94 Container::make( 'post_meta', __( 'Configuration', 'bookiflex' ) )->where( 'post_type', '=', self::POST_TYPE )->add_fields( $paymentSettingsFields ); 69 95 } 70 96 -
bookiflex/tags/1.2.0/src/Admin/CPT/RatePlan.php
r3478607 r3495560 18 18 use BookiFlex\Core\Admin\CPT\PaymentType; 19 19 use BookiFlex\Core\Admin\CPT\RatePlan as BaseCPT; 20 use BookiFlex\Core\Admin\Field\SectionNotice; 20 21 use BookiFlex\Core\Contract\PluginInterface; 21 22 use BookiFlex\Core\Model\AccommodationType\AccommodationPlacementTypeInterface; … … 23 24 use BookiFlex\Core\Model\RatePlan\BoardTypeInterface; 24 25 use BookiFlex\Core\Util\ProFeature; 26 use BookiFlex\Core\Admin\Field\RadioCard; 25 27 use BookiFlex\Extensions\Onboarding\Contract\OnboardingPresetsProviderInterface; 26 28 use Carbon_Fields\Container; … … 35 37 public function register( PluginInterface $plugin ) : void { 36 38 parent::register( $plugin ); 39 $this->customizeMenuOrder( __( 'Display order', 'bookiflex' ), __( 'Controls the display order of this rate plan. Lower numbers appear first.', 'bookiflex' ) ); 40 if ( $this->supportInheritance() ) { 41 $this->customizeParentSelector( __( 'Parent rate plan', 'bookiflex' ), __( 'Select a parent rate plan to inherit prices and restrictions from.', 'bookiflex' ) ); 42 } 43 $this->customizeExcerpt( __( 'Description', 'bookiflex' ), __( 'A brief description of this rate plan. This text may be shown to guests during the booking process.', 'bookiflex' ) ); 37 44 $this->plugin->addAction( 38 45 'carbon_fields_post_meta_container_saved', … … 49 56 50 57 public function registerMetaBoxes() : void { 51 $generalFields = [ 52 Field::make( 'text', self::FIELD_SHORT_CODE, __( 'Short code', 'bookiflex' ) )->set_width( 50 )->set_attribute( 'maxLength', '10' )->set_attribute( 'readOnly', 'true' )->help_text( __( 'A short identifier for this rate plan (generated automatically). For example: BRP for Base rate plan, SAM for Summer vacation rate plan. This code may be used internally or in reports.', 'bookiflex' ) ), 53 Field::make( 'hidden', self::FIELD_BOARD_TYPE, '' )->set_default_value( BoardTypeInterface::ROOM_ONLY ), 54 Field::make( 'separator', 'bflex_rental_units_separator', __( 'Rental units', 'bookiflex' ) ), 55 Field::make( 'html', 'rental-units-html' )->set_html( sprintf( '<p>%s</p>', __( 'Select the rental units this rate plan applies to. You\'ll be able to define prices and restrictions for each one separately.', 'bookiflex' ) ) ), 56 Field::make( 'association', self::FIELD_ACCOMMODATION_TYPES, '' )->set_required()->set_types( [[ 57 'type' => 'post', 58 'post_type' => AccommodationType::POST_TYPE, 59 ]] ) 60 ]; 61 Container::make( 'post_meta', 'rate-plan-fields', __( 'Configuration', 'bookiflex' ) )->where( 'post_type', '=', self::POST_TYPE )->add_tab( __( 'General', 'bookiflex' ), $generalFields )->add_tab( __( 'Booking terms', 'bookiflex' ), $this->buildBookingTermsFields() ); 58 $generalFields = [Field::make( 'hidden', self::FIELD_BOARD_TYPE, '' )->set_default_value( BoardTypeInterface::ROOM_ONLY ), SectionNotice::make( 'bflex__rp__accommodation_types-html', sprintf( '<strong>%s</strong> %s', __( 'Select the rental units this rate plan applies to.', 'bookiflex' ), __( 'You\'ll be able to define prices and restrictions for each one separately.', 'bookiflex' ) ) ), Field::make( 'association', self::FIELD_ACCOMMODATION_TYPES, '' )->set_required()->set_types( [[ 59 'type' => 'post', 60 'post_type' => AccommodationType::POST_TYPE, 61 ]] )]; 62 Container::make( 'post_meta', 'rate-plan-short-code', __( 'Short code', 'bookiflex' ) )->where( 'post_type', '=', self::POST_TYPE )->set_context( 'side' )->add_fields( [Field::make( 'text', self::FIELD_SHORT_CODE, '' )->set_attribute( 'maxLength', '10' )->set_attribute( 'readOnly', 'true' )->help_text( __( 'A short identifier for this rate plan (generated automatically). For example: BRP for Base rate plan, SAM for Summer vacation rate plan. This code may be used internally or in reports.', 'bookiflex' ) )] ); 63 Container::make( 'post_meta', 'rate-plan-fields', __( 'Configuration', 'bookiflex' ) )->set_layout( 'tabbed-vertical' )->where( 'post_type', '=', self::POST_TYPE )->add_tab( __( 'General', 'bookiflex' ), $generalFields )->add_tab( __( 'Booking terms', 'bookiflex' ), $this->buildBookingTermsFields() ); 62 64 $this->showNotice(); 63 65 } … … 74 76 private function buildBookingTermsFields() : array { 75 77 $fields = []; 76 $fields[] = Field::make( 'html', 'booking-terms-html' )->set_html( sprintf( '<p>%s</p>', __( 'Choose how guests pay and what cancellation rules apply to this rate plan.', 'bookiflex' ) ) ); 77 $fields[] = Field::make( 'radio', self::FIELD_BOOKING_TERMS, '' )->set_options( function () { 78 return $this->getAvailableBookingTermsOptions(); 79 } )->set_default_value( $this->getDefaultBookingTermsValue() ); 80 // Add conditional description blocks for each preset 78 $fields[] = SectionNotice::make( 'booking-terms-html', __( 'Choose how guests pay and what cancellation rules apply to this rate plan.', 'bookiflex' ) ); 79 // Build RadioCard options from presets 80 $options = []; 81 81 $presets = $this->presetsProvider->getBookingPresets(); 82 82 foreach ( $presets as $preset ) { 83 $html = sprintf( '<div style="padding: 12px 16px; background: #f0f6fc; border-left: 4px solid #0073aa; margin: 8px 0;"> 84 <p style="margin: 0 0 6px;">%s</p> 85 <p style="margin: 0; color: #555; font-style: italic;">%s</p> 86 </div>', esc_html( $preset['shortDescription'] ), esc_html( $preset['recommendation'] ) ); 87 $fields[] = Field::make( 'html', 'preset_' . $preset['id'] . '_desc' )->set_html( $html )->set_conditional_logic( [[ 88 'field' => self::FIELD_BOOKING_TERMS, 89 'value' => $preset['id'], 90 ]] ); 91 } 92 // Custom description 93 $fields[] = Field::make( 'html', 'custom_booking_terms_desc' )->set_html( sprintf( '<div style="padding: 12px 16px; background: #fff8e5; border-left: 4px solid #dba617; margin: 8px 0;"> 94 <p style="margin: 0;">%s</p> 95 </div>', esc_html__( 'Manually select the payment method(s) and cancellation policy for this rate plan.', 'bookiflex' ) ) )->set_conditional_logic( [[ 83 $paymentTypeId = $this->findCptByPresetKey( PaymentType::POST_TYPE, $preset['paymentTypeKey'] ); 84 $cancellationPolicyId = $this->findCptByPresetKey( CancellationPolicy::POST_TYPE, $preset['cancellationPolicyKey'] ); 85 if ( $paymentTypeId && $cancellationPolicyId ) { 86 $title = $preset['title']; 87 if ( !empty( $preset['popular'] ) ) { 88 $title .= ' ' . __( '(recommended)', 'bookiflex' ); 89 } 90 $description = $preset['shortDescription']; 91 if ( !empty( $preset['recommendation'] ) ) { 92 $description .= ' ' . $preset['recommendation']; 93 } 94 $options[$preset['id']] = [ 95 'title' => $title, 96 'description' => $description, 97 ]; 98 } 99 } 100 $options['custom'] = [ 101 'title' => __( 'Custom', 'bookiflex' ), 102 'description' => __( 'Manually select the payment method(s) and cancellation policy for this rate plan.', 'bookiflex' ), 103 ]; 104 $default = $this->getDefaultBookingTermsValue(); 105 array_push( $fields, ...RadioCard::make( 106 self::FIELD_BOOKING_TERMS, 107 __( 'Booking terms', 'bookiflex' ), 108 $options, 109 $default, 110 true 111 ) ); 112 // Association fields — visible only for Custom 113 $fields[] = Field::make( 'separator', 'bflex__cp__strict_separator', __( 'Configuration', 'bookiflex' ) )->set_conditional_logic( [[ 96 114 'field' => self::FIELD_BOOKING_TERMS, 97 115 'value' => 'custom', 98 116 ]] ); 99 // Association fields — visible only for Custom100 117 $fields[] = Field::make( 'association', self::FIELD_PAYMENT_TYPES, __( 'Payment types', 'bookiflex' ) )->set_types( [[ 101 118 'type' => 'post', … … 116 133 117 134 /** 118 * Get available booking terms options for radio field. 119 * 120 * Only includes presets for which both PaymentType and CancellationPolicy CPTs 121 * with matching `_bflex_preset_key` exist in the database. 122 * 123 * @return array<string, string> 124 */ 125 private function getAvailableBookingTermsOptions() : array { 135 * Get default value for booking terms radio. 136 * 137 * Returns the first available preset id, or 'custom' if none available. 138 * 139 * @return string 140 */ 141 private function getDefaultBookingTermsValue() : string { 126 142 $presets = $this->presetsProvider->getBookingPresets(); 127 $options = [];128 143 foreach ( $presets as $preset ) { 129 144 $paymentTypeId = $this->findCptByPresetKey( PaymentType::POST_TYPE, $preset['paymentTypeKey'] ); 130 145 $cancellationPolicyId = $this->findCptByPresetKey( CancellationPolicy::POST_TYPE, $preset['cancellationPolicyKey'] ); 131 146 if ( $paymentTypeId && $cancellationPolicyId ) { 132 $label = $preset['title']; 133 if ( !empty( $preset['popular'] ) ) { 134 $label .= ' ' . __( '(recommended)', 'bookiflex' ); 135 } 136 $options[$preset['id']] = $label; 137 } 138 } 139 $options['custom'] = __( 'Custom', 'bookiflex' ); 140 return $options; 141 } 142 143 /** 144 * Get default value for booking terms radio. 145 * 146 * Returns the first available preset id, or 'custom' if none available. 147 * 148 * @return string 149 */ 150 private function getDefaultBookingTermsValue() : string { 151 $options = $this->getAvailableBookingTermsOptions(); 152 $keys = array_keys( $options ); 153 // Return first non-custom option, or 'custom' 154 foreach ( $keys as $key ) { 155 if ( $key !== 'custom' ) { 156 return $key; 147 return $preset['id']; 157 148 } 158 149 } -
bookiflex/tags/1.2.0/src/Core/Admin/CPT/AbstractCPT.php
r3478607 r3495560 43 43 $query->set('order', 'ASC'); 44 44 } 45 } 46 47 protected function customizeMenuOrder(string $title, string $description): void 48 { 49 $this->plugin->addAction('add_meta_boxes', function () use ($title, $description) { 50 add_meta_box( 51 'bflex_' . static::POST_TYPE . '_menu_order', 52 $title, 53 function ($post) use ($description) { 54 echo '<input name="menu_order" type="number" min="0" id="menu_order" value="' . esc_attr($post->menu_order) . '" style="width:100%" />'; 55 echo '<p class="description">' . esc_html($description) . '</p>'; 56 }, 57 static::POST_TYPE, 58 'side' 59 ); 60 }); 61 } 62 63 protected function customizeParentSelector(string $title, string $description): void 64 { 65 $this->plugin->addAction('add_meta_boxes', function () use ($title, $description) { 66 add_meta_box( 67 'bflex_' . static::POST_TYPE . '_parent', 68 $title, 69 function ($post) use ($description) { 70 $dropdown = wp_dropdown_pages([ 71 'post_type' => $post->post_type, 72 'exclude_tree' => $post->ID, 73 'selected' => $post->post_parent, 74 'name' => 'parent_id', 75 'show_option_none' => __('(no parent)', 'bookiflex'), 76 'sort_column' => 'menu_order, post_title', 77 'echo' => 0, 78 ]); 79 if ($dropdown) { 80 echo $dropdown; 81 } 82 echo '<p class="description">' . esc_html($description) . '</p>'; 83 }, 84 static::POST_TYPE, 85 'side' 86 ); 87 }); 88 } 89 90 protected function customizeExcerpt(string $title, string $description): void 91 { 92 $this->plugin->addAction('add_meta_boxes', function () use ($title, $description) { 93 add_meta_box( 94 'bflex_' . static::POST_TYPE . '_excerpt', 95 $title, 96 function ($post) use ($title, $description) { 97 ?> 98 <label class="screen-reader-text" for="excerpt"><?php echo esc_html($title); ?></label> 99 <textarea rows="1" cols="40" name="excerpt" id="excerpt"><?php echo esc_html($post->post_excerpt); ?></textarea> 100 <p><?php echo esc_html($description); ?></p> 101 <?php 102 }, 103 static::POST_TYPE, 104 'normal' 105 ); 106 }); 45 107 } 46 108 -
bookiflex/tags/1.2.0/src/Core/Admin/CPT/AccommodationType.php
r3478607 r3495560 56 56 // Register event hooks from trait 57 57 $this->registerEventHooks(); 58 59 // Thumbnail column in list table 60 $this->plugin->addFilter('manage_' . self::POST_TYPE . '_posts_columns', [$this, 'addThumbnailColumn']); 61 $this->plugin->addAction('manage_' . self::POST_TYPE . '_posts_custom_column', [$this, 'renderThumbnailColumn'], 10, 2); 62 } 63 64 /** 65 * Insert "Image" column before "title" 66 */ 67 public function addThumbnailColumn(array $columns): array 68 { 69 $result = []; 70 71 foreach ($columns as $key => $label) { 72 if ($key === 'title') { 73 $result['bflex_thumbnail'] = __('Image', 'bookiflex'); 74 } 75 $result[$key] = $label; 76 } 77 78 return $result; 79 } 80 81 /** 82 * Render thumbnail or placeholder in list column 83 */ 84 public function renderThumbnailColumn(string $column, int $postId): void 85 { 86 if ($column !== 'bflex_thumbnail') { 87 return; 88 } 89 90 if (has_post_thumbnail($postId)) { 91 echo get_the_post_thumbnail($postId, [80, 80]); 92 } else { 93 echo '<span class="bflex-thumbnail-placeholder dashicons dashicons-format-image"></span>'; 94 } 58 95 } 59 96 … … 99 136 'hierarchical' => false, 100 137 'menu_position' => 0, 101 'supports' => ['title', ' excerpt', 'thumbnail', 'page-attributes'],138 'supports' => ['title', 'thumbnail'], 102 139 'capability_type' => self::POST_TYPE, 103 140 'capabilities' => [ -
bookiflex/tags/1.2.0/src/Core/Admin/CPT/CancellationPolicy.php
r3478607 r3495560 16 16 namespace BookiFlex\Core\Admin\CPT; 17 17 18 use BookiFlex\Core\Contract\PluginInterface; 18 19 use BookiFlex\Core\Contract\RoleCapabilitiesInterface; 19 20 … … 43 44 public const FIELD_STRICT_TIME_WINDOW = 'bflex__cp__strict_time_window'; 44 45 public const FIELD_STRICT_PENALTY_PERCENT = 'bflex__cp__strict_penalty_percent'; 46 47 public function register(PluginInterface $plugin): void 48 { 49 parent::register($plugin); 50 51 $this->customizeExcerpt( 52 __('Description', 'bookiflex'), 53 __('An optional note for your own reference. This text is not shown to guests.', 'bookiflex') 54 ); 55 } 45 56 46 57 public function registerPostType(): void … … 80 91 'hierarchical' => false, 81 92 'menu_position' => 2, 82 'supports' => ['title' , 'excerpt'],93 'supports' => ['title'], 83 94 'capability_type' => self::POST_TYPE, 84 95 'capabilities' => [ -
bookiflex/tags/1.2.0/src/Core/Admin/CPT/PaymentType.php
r3478607 r3495560 78 78 'hierarchical' => false, 79 79 'menu_position' => 3, 80 'supports' => ['title' , 'excerpt'],80 'supports' => ['title'], 81 81 'capability_type' => self::POST_TYPE, 82 82 'capabilities' => [ -
bookiflex/tags/1.2.0/src/Core/Admin/CPT/RatePlan.php
r3478607 r3495560 85 85 'hierarchical' => $this->supportInheritance(), 86 86 'menu_position' => 1, 87 'supports' => ['title' , 'excerpt', 'page-attributes'],87 'supports' => ['title'], 88 88 'capability_type' => self::POST_TYPE, 89 89 'capabilities' => [ -
bookiflex/tags/1.2.0/vendor/composer/autoload_classmap.php
r3478614 r3495560 24 24 'BookiFlex\\Core\\Admin\\CTL\\CustomerTableList' => $baseDir . '/src/Core/Admin/CTL/CustomerTableList.php', 25 25 'BookiFlex\\Core\\Admin\\CTL\\ReservationTableList' => $baseDir . '/src/Core/Admin/CTL/ReservationTableList.php', 26 'BookiFlex\\Core\\Admin\\Field\\RadioCard' => $baseDir . '/src/Core/Admin/Field/RadioCard.php', 27 'BookiFlex\\Core\\Admin\\Field\\SectionNotice' => $baseDir . '/src/Core/Admin/Field/SectionNotice.php', 26 28 'BookiFlex\\Core\\Admin\\Lifecycle\\AbstractExtensionActivator' => $baseDir . '/src/Core/Admin/Lifecycle/AbstractExtensionActivator.php', 27 29 'BookiFlex\\Core\\Admin\\Lifecycle\\AbstractUninstaller' => $baseDir . '/src/Core/Admin/Lifecycle/AbstractUninstaller.php', -
bookiflex/tags/1.2.0/vendor/composer/autoload_static.php
r3483810 r3495560 456 456 'BookiFlex\\Core\\Admin\\CTL\\CustomerTableList' => __DIR__ . '/../..' . '/src/Core/Admin/CTL/CustomerTableList.php', 457 457 'BookiFlex\\Core\\Admin\\CTL\\ReservationTableList' => __DIR__ . '/../..' . '/src/Core/Admin/CTL/ReservationTableList.php', 458 'BookiFlex\\Core\\Admin\\Field\\RadioCard' => __DIR__ . '/../..' . '/src/Core/Admin/Field/RadioCard.php', 459 'BookiFlex\\Core\\Admin\\Field\\SectionNotice' => __DIR__ . '/../..' . '/src/Core/Admin/Field/SectionNotice.php', 458 460 'BookiFlex\\Core\\Admin\\Lifecycle\\AbstractExtensionActivator' => __DIR__ . '/../..' . '/src/Core/Admin/Lifecycle/AbstractExtensionActivator.php', 459 461 'BookiFlex\\Core\\Admin\\Lifecycle\\AbstractUninstaller' => __DIR__ . '/../..' . '/src/Core/Admin/Lifecycle/AbstractUninstaller.php', -
bookiflex/tags/1.2.0/vendor/composer/installed.php
r3493377 r3495560 2 2 'root' => array( 3 3 'name' => 'bookiflex/plugin', 4 'pretty_version' => 'v1. 1.1',5 'version' => '1. 1.1.0',6 'reference' => ' 198f1b412b1060aca0e245573237bc45105d1d82',4 'pretty_version' => 'v1.2.0', 5 'version' => '1.2.0.0', 6 'reference' => 'b01ef3c27da8b2bf4bde963764fcc52c71eeb6db', 7 7 'type' => 'wordpress-plugin', 8 8 'install_path' => __DIR__ . '/../../', … … 21 21 ), 22 22 'bookiflex/plugin' => array( 23 'pretty_version' => 'v1. 1.1',24 'version' => '1. 1.1.0',25 'reference' => ' 198f1b412b1060aca0e245573237bc45105d1d82',23 'pretty_version' => 'v1.2.0', 24 'version' => '1.2.0.0', 25 'reference' => 'b01ef3c27da8b2bf4bde963764fcc52c71eeb6db', 26 26 'type' => 'wordpress-plugin', 27 27 'install_path' => __DIR__ . '/../../', -
bookiflex/trunk/assets/manifest.json
r3493377 r3495560 1 1 { 2 "version": "1. 1.1",3 "generated": "2026-03- 28T14:15:22.310Z",2 "version": "1.2.0", 3 "generated": "2026-03-31T12:43:23.451Z", 4 4 "external": { 5 5 "vue": "assets/vendor/vue/vue.global.prod.js", … … 15 15 }, 16 16 "admin": { 17 "js": "assets/free/admin/index. B_cl0VpC.js",18 "css": "assets/free/admin/style. B9Y7Sqrs.css"17 "js": "assets/free/admin/index.D9SCTotr.js", 18 "css": "assets/free/admin/style.CEmLATbJ.css" 19 19 }, 20 20 "widgets": { 21 21 "controller": { 22 "js": "assets/common/widgets/controller/index.B 2RbsrGV.js"22 "js": "assets/common/widgets/controller/index.B3SGvgXg.js" 23 23 }, 24 24 "booking": { -
bookiflex/trunk/bookiflex.php
r3493377 r3495560 6 6 * Description: Direct Booking Widget for Apartments and Short-Term Rentals 7 7 * Plugin URI: https://bookiflex.com 8 * Version: 1. 1.18 * Version: 1.2.0 9 9 * Author: BookiFlex 10 10 * License: GPL-2.0-or-later … … 80 80 } 81 81 // Define plugin constants 82 define( 'BOOKIFLEX_VERSION', '1. 1.1' );82 define( 'BOOKIFLEX_VERSION', '1.2.0' ); 83 83 define( 'BOOKIFLEX_FILE', __FILE__ ); 84 84 define( 'BOOKIFLEX_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); -
bookiflex/trunk/readme.txt
r3493377 r3495560 5 5 Tested up to: 6.9 6 6 Requires PHP: 8.1 7 Stable tag: 1. 1.17 Stable tag: 1.2.0 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 149 149 == Changelog == 150 150 151 = 1.1.1 = 152 * Fix a problem with Notifications when VAT is enabled 153 154 = 1.1.0 = 155 * Improve interface behavior (search widget) 156 * Fix minor bugs 157 158 = 1.0.2 = 159 * Fix onboarding flow 160 161 = 1.0.0 = 162 * Initial release 163 * Floating booking button and modal widget 164 * Room setup, pricing, availability, and email notifications 151 = 1.2.0 - 31 March 2026 = 152 * Improved: Redesigned admin panel for better usability and cleaner interface 153 * Improved: Added class attributes to modal trigger elements for easier customization 154 * Fixed: Offers now load correctly when clicking custom trigger elements 155 * Fixed: Admin nonce now refreshes automatically to prevent expired session errors 156 157 [See changelog for all versions](https://plugins.svn.wordpress.org/bookiflex/trunk/CHANGELOG.txt). 165 158 166 159 -
bookiflex/trunk/src/Admin/AssetsManager.php
r3487384 r3495560 46 46 // Vue — single path, dev manifest overrides prod vue path 47 47 $this->enqueueScript( 'bookiflex-vue', $this->assetUrl( $this->asset( 'external', 'vue' ) ), ['wp-i18n'] ); 48 // Carbon fields style 49 $this->enqueueStyle( 'carbon-fields-style', $this->assetUrl( 'assets/vendor/carbon_fields/style.css' ), ['carbon-fields-metaboxes'] ); 50 // Radio card field 51 $this->enqueueScript( 52 'bookiflex-radio-card', 53 $this->assetUrl( 'assets/vendor/carbon_fields/radio-card.js' ), 54 ['carbon-fields-vendor', 'carbon-fields-core', 'carbon-fields-metaboxes'], 55 true 56 ); 48 57 $this->enqueueAdminApp(); 49 58 wp_set_script_translations( 'bookiflex-admin-app', 'bookiflex', $this->plugin->getPluginDir() . 'languages' ); -
bookiflex/trunk/src/Admin/CPT/AccommodationType.php
r3478607 r3495560 15 15 16 16 use BookiFlex\Core\Admin\CPT\AccommodationType as BaseCPT; 17 use BookiFlex\Core\Contract\PluginInterface; 17 18 use BookiFlex\Core\Model\AccommodationType\BookingUnitTypeInterface; 18 19 use BookiFlex\Core\Util\ProFeature; … … 21 22 defined( 'ABSPATH' ) || exit; 22 23 class AccommodationType extends BaseCPT { 24 public function register( PluginInterface $plugin ) : void { 25 parent::register( $plugin ); 26 $this->customizeMenuOrder( __( 'Display order', 'bookiflex' ), __( 'Controls the display order of this rental unit on the booking widget. Lower numbers appear first.', 'bookiflex' ) ); 27 $this->customizeExcerpt( __( 'Description', 'bookiflex' ), __( 'A brief description of this unit. This text may be shown to guests during the booking process.', 'bookiflex' ) ); 28 } 29 23 30 public function registerMetaBoxes() : void { 24 31 $overviewFields = [ 25 Field::make( 'text', self::FIELD_ SHORT_CODE, __( 'Short code', 'bookiflex' ) )->set_width( 34 )->set_attribute( 'maxLength', '10' )->set_attribute( 'readOnly', 'true' )->set_attribute( 'placeholder', __( 'e.g. STD', 'bookiflex' ) )->help_text( __( 'A short identifier for this rental unit (generated automatically). For example: APT for Apartment, CAB for Cabin. This code may be used internally or in reports.', 'bookiflex' ) ),32 Field::make( 'text', self::FIELD_ADDRESS, __( 'Address', 'bookiflex' ) )->set_required()->set_help_text( __( 'The full address of the property.', 'bookiflex' ) ), 26 33 Field::make( 'text', self::FIELD_LIVING_SPACE, __( 'Living space', 'bookiflex' ) )->set_width( 33 )->set_attribute( 'placeholder', __( 'e.g. 30 m², 250 ft², 45', 'bookiflex' ) )->help_text( __( 'Specify the total living area of the rental unit (in square meters, square feet, or any unit you prefer). This information is often displayed on the unit page.', 'bookiflex' ) ), 27 34 Field::make( 'text', self::FIELD_ROOMS_COUNT, __( 'Number of rooms', 'bookiflex' ) )->set_width( 33 )->set_attribute( 'type', 'number' )->set_attribute( 'min', '1' )->set_attribute( 'placeholder', __( 'e.g. 3', 'bookiflex' ) )->help_text( __( 'Total number of separate rooms in this rental unit (bedrooms, living room, kitchen, etc.).', 'bookiflex' ) ), … … 32 39 $guestsBedFields = [Field::make( 'separator', 'bflex_main_placement_separator', __( 'Main placements', 'bookiflex' ) ), Field::make( 'select', self::FIELD_MAIN_SLEEPING_CAPACITY, __( 'Main sleeping capacity', 'bookiflex' ) )->set_width( 50 )->set_options( array_combine( range( 1, 10 ), range( 1, 10 ) ) )->set_default_value( 2 )->help_text( __( 'Enter the total number of main sleeping places (e.g., 1 double bed = 2 places).', 'bookiflex' ) ), Field::make( 'set', self::FIELD_MAIN_SLEEPING_ALLOWED_OCCUPANCY, __( 'Allowed occupancy', 'bookiflex' ) )->set_width( 50 )->set_options( array_combine( range( 1, 10 ), range( 1, 10 ) ) )->help_text( __( 'Select how many guests can stay in this accommodation. Each selected option can have its own price. <strong>Only selected occupancy options will be available for booking and pricing.</strong>', 'bookiflex' ) )]; 33 40 $guestsBedFields = array_merge( $guestsBedFields, $this->addNotice() ); 34 Container::make( 'post_meta', 'at_configuration', __( 'Configuration', 'bookiflex' ) )->where( 'post_type', '=', self::POST_TYPE )->add_tab( __( 'Overview', 'bookiflex' ), $overviewFields )->add_tab( __( 'Guests & beds', 'bookiflex' ), $guestsBedFields )->add_tab( __( 'Contact information', 'bookiflex' ), [ 35 Field::make( 'separator', 'bflex_unit_address_separator', __( 'Rental unit address', 'bookiflex' ) ), 36 Field::make( 'text', self::FIELD_ADDRESS, __( 'Address', 'bookiflex' ) )->set_required()->set_help_text( __( 'The full address of the property.', 'bookiflex' ) ), 37 Field::make( 'text', self::FIELD_LONGITUDE, __( 'Longitude', 'bookiflex' ) )->set_width( 50 )->set_help_text( __( 'Used to display the property on a map.', 'bookiflex' ) ), 38 Field::make( 'text', self::FIELD_LATITUDE, __( 'Latitude', 'bookiflex' ) )->set_width( 50 )->set_help_text( __( 'Used to display the property on a map.', 'bookiflex' ) ), 39 Field::make( 'separator', 'bflex_unit_email_separator', __( 'Email information', 'bookiflex' ) ), 41 Container::make( 'post_meta', 'at_short_code', __( 'Short code', 'bookiflex' ) )->where( 'post_type', '=', self::POST_TYPE )->set_context( 'side' )->add_fields( [Field::make( 'text', self::FIELD_SHORT_CODE, '' )->set_attribute( 'maxLength', '10' )->set_attribute( 'readOnly', 'true' )->set_attribute( 'placeholder', __( 'e.g. STD', 'bookiflex' ) )->help_text( __( 'A short identifier for this rental unit (generated automatically). For example: APT for Apartment, CAB for Cabin. This code may be used internally or in reports.', 'bookiflex' ) )] ); 42 Container::make( 'post_meta', 'at_configuration', __( 'Configuration', 'bookiflex' ) )->where( 'post_type', '=', self::POST_TYPE )->set_layout( 'tabbed-vertical' )->add_tab( __( 'Overview', 'bookiflex' ), $overviewFields )->add_tab( __( 'Guests & beds', 'bookiflex' ), $guestsBedFields )->add_tab( __( 'Email information', 'bookiflex' ), [ 40 43 Field::make( 'text', self::FIELD_PHONE, __( 'Phone Number', 'bookiflex' ) )->set_width( 50 )->set_attribute( 'type', 'tel' )->set_help_text( __( 'For guest support and communication (if not specified, the default one will be used).', 'bookiflex' ) ), 41 44 Field::make( 'text', self::FIELD_EMAIL, __( 'Email', 'bookiflex' ) )->set_width( 50 )->set_attribute( 'type', 'email' )->set_help_text( __( 'For guest support and communication (if not specified, the default one will be used).', 'bookiflex' ) ), 42 Field::make( 'textarea', self::FIELD_CHECKIN_INSTRUCTIONS, __( 'Check-in instructions', 'bookiflex' ) )->set_rows( 4 )->help_text( __( 'Important information sent to guests after booking confirmation. Include details like door codes, parking instructions, key pickup location, or check-in procedures specific to this rental unit.', 'bookiflex' ) ) 45 Field::make( 'textarea', self::FIELD_CHECKIN_INSTRUCTIONS, __( 'Check-in instructions', 'bookiflex' ) )->set_rows( 4 )->help_text( __( 'Important information sent to guests after booking confirmation. Include details like door codes, parking instructions, key pickup location, or check-in procedures specific to this rental unit.', 'bookiflex' ) ), 46 Field::make( 'separator', 'bflex_unit_address_separator', __( 'Map coordinates', 'bookiflex' ) ), 47 Field::make( 'text', self::FIELD_LONGITUDE, __( 'Longitude', 'bookiflex' ) )->set_width( 50 )->set_help_text( __( 'Used to display the property on a map.', 'bookiflex' ) ), 48 Field::make( 'text', self::FIELD_LATITUDE, __( 'Latitude', 'bookiflex' ) )->set_width( 50 )->set_help_text( __( 'Used to display the property on a map.', 'bookiflex' ) ) 43 49 ] ); 44 50 Container::make( 'post_meta', __( 'Gallery', 'bookiflex' ) )->where( 'post_type', '=', self::POST_TYPE )->add_fields( [Field::make( 'media_gallery', self::FIELD_ACCOMMODATION_GALLERY, __( 'Gallery', 'bookiflex' ) )] ); -
bookiflex/trunk/src/Admin/CPT/CancellationPolicy.php
r3478607 r3495560 17 17 use BookiFlex\Core\Contract\CancellationPolicy\CancellationPolicyTypeInterface; 18 18 use BookiFlex\Core\Util\ProFeature; 19 use BookiFlex\Core\Admin\Field\RadioCard; 20 use BookiFlex\Core\Admin\Field\SectionNotice; 19 21 use Carbon_Fields\Container; 20 22 use Carbon_Fields\Field; … … 22 24 class CancellationPolicy extends BaseCPT { 23 25 public function registerMetaBoxes() : void { 24 // Build policy options 26 // Build policy options with descriptions for radio cards 25 27 $policyOptions = [ 26 self::RULE_FULLY_FLEXIBLE => __( 'Fully flexible', 'bookiflex' ), 27 self::RULE_STRICT => __( 'Strict', 'bookiflex' ), 28 self::RULE_FIRST_NIGHT => __( 'First night penalty', 'bookiflex' ), 29 self::RULE_NON_REFUNDABLE => __( 'Non-refundable', 'bookiflex' ), 28 self::RULE_FULLY_FLEXIBLE => [ 29 'title' => __( 'Fully flexible', 'bookiflex' ), 30 'description' => __( 'Free cancellation at any time, no penalty will be charged.', 'bookiflex' ), 31 ], 32 self::RULE_STRICT => [ 33 'title' => __( 'Strict', 'bookiflex' ), 34 'description' => __( 'Configurable cancellation with custom time window and penalty percentage.', 'bookiflex' ), 35 ], 36 self::RULE_FIRST_NIGHT => [ 37 'title' => __( 'First night penalty', 'bookiflex' ), 38 'description' => __( 'Cancellation at any time will incur a penalty equal to the first night\'s stay.', 'bookiflex' ), 39 ], 40 self::RULE_NON_REFUNDABLE => [ 41 'title' => __( 'Non-refundable', 'bookiflex' ), 42 'description' => __( 'Cancellation at any time will incur a 100% charge of the booking amount.', 'bookiflex' ), 43 ], 30 44 ]; 31 45 $fields = [ 32 Field::make( 'html', 'cancellation_policy_html' )->set_html( sprintf( '<p>%s</p>', __( 'A cancellation policy defines how and when cancellation penalties apply. Later, this policy can be assigned to a rate plan.', 'bookiflex' ) ) ), 33 Field::make( 'radio', self::FIELD_PREDEFINED_RULE, __( 'Rule', 'bookiflex' ) )->set_width( 50 )->set_help_text( __( 'Chose one of predefined policies.', 'bookiflex' ) )->set_options( $policyOptions ), 34 Field::make( 'html', self::FIELD_PREDEFINED_RULE . '_html' )->set_width( 50 )->set_html( sprintf( '<p><strong>%s</strong> - %s</p>', __( 'Fully flexible', 'bookiflex' ), __( 'Free cancellation at any time, no penalty will be charged.', 'bookiflex' ) ) . sprintf( '<p><strong>%s</strong> - %s</p>', __( 'Strict', 'bookiflex' ), __( 'Configurable cancellation with custom time window and penalty percentage.', 'bookiflex' ) ) . sprintf( '<p><strong>%s</strong> - %s</p>', __( 'First night penalty', 'bookiflex' ), __( 'Cancellation at any time will incur a penalty equal to the first night\'s stay.', 'bookiflex' ) ) . sprintf( '<p><strong>%s</strong> - %s</p>', __( 'Non-refundable', 'bookiflex' ), __( 'Cancellation at any time will incur a 100% charge of the booking amount.', 'bookiflex' ) ) ), 46 SectionNotice::make( 'cancellation_policy_html', __( 'A cancellation policy defines how and when cancellation penalties apply. Later, this policy can be assigned to a rate plan.', 'bookiflex' ) ), 47 ...RadioCard::make( 48 self::FIELD_PREDEFINED_RULE, 49 __( 'Rule', 'bookiflex' ), 50 $policyOptions, 51 self::RULE_FULLY_FLEXIBLE 52 ), 53 Field::make( 'separator', 'bflex__cp__strict_separator', __( 'Configuration', 'bookiflex' ) )->set_conditional_logic( [[ 54 'field' => self::FIELD_PREDEFINED_RULE, 55 'value' => self::RULE_STRICT, 56 ]] ), 35 57 Field::make( 'select', self::FIELD_STRICT_TIME_WINDOW, __( 'Cancellation window', 'bookiflex' ) )->set_conditional_logic( [[ 36 58 'field' => self::FIELD_PREDEFINED_RULE, -
bookiflex/trunk/src/Admin/CPT/PaymentType.php
r3478607 r3495560 15 15 16 16 use BookiFlex\Core\Admin\CPT\PaymentType as BaseCPT; 17 use BookiFlex\Core\Admin\Field\RadioCard; 18 use BookiFlex\Core\Admin\Field\SectionNotice; 19 use BookiFlex\Core\Contract\PluginInterface; 17 20 use BookiFlex\Core\Model\PaymentType\PaymentTypeInterface; 18 21 use BookiFlex\Core\Util\ProFeature; … … 21 24 defined( 'ABSPATH' ) || exit; 22 25 class PaymentType extends BaseCPT { 26 public function register( PluginInterface $plugin ) : void { 27 parent::register( $plugin ); 28 $this->customizeExcerpt( __( 'Description', 'bookiflex' ), __( 'A brief description of this payment type. This text may be shown to guests during the booking process.', 'bookiflex' ) ); 29 } 30 23 31 public function registerMetaBoxes() : void { 24 32 $paymentGateways = $this->getPaymentGateways(); 25 33 // Build payment settings fields 26 34 $paymentSettingsFields = [ 27 Field::make( 'radio', self::FIELD_CALCULATOR_TYPE, __( 'How will the payment be collected?', 'bookiflex' ) )->set_width( 50 )->set_help_text( __( 'Choose when the booking gets confirmed. Options requiring payment will hold the booking until the guest pays within the allowed time — if not paid, the booking is canceled and availability is restored. Options without payment requirement confirm the booking immediately.', 'bookiflex' ) )->set_options( [ 28 PaymentTypeInterface::PAYMENT_ON_ARRIVAL_TYPE => __( 'Guest pays on arrival', 'bookiflex' ), 29 PaymentTypeInterface::BANK_PAYMENT_TYPE => __( 'Bank transfer (confirmed without payment)', 'bookiflex' ), 30 PaymentTypeInterface::BANK_PAYMENT_PAYABLE_TYPE => __( 'Bank transfer (payment required to confirm)', 'bookiflex' ), 31 PaymentTypeInterface::INTERNET_PAYMENT_TYPE => __( 'Guest pays online (via payment gateway)', 'bookiflex' ), 32 ] ), 35 SectionNotice::make( 'payment_type_notice', __( 'Choose when the booking gets confirmed. Options requiring payment will hold the booking until the guest pays within the allowed time — if not paid, the booking is canceled and availability is restored. Options without payment requirement confirm the booking immediately.', 'bookiflex' ) ), 36 ...RadioCard::make( 37 self::FIELD_CALCULATOR_TYPE, 38 __( 'How will the payment be collected?', 'bookiflex' ), 39 [ 40 PaymentTypeInterface::PAYMENT_ON_ARRIVAL_TYPE => [ 41 'title' => __( 'Guest pays on arrival', 'bookiflex' ), 42 'description' => __( 'Booking is confirmed immediately. No online payment required.', 'bookiflex' ), 43 ], 44 PaymentTypeInterface::BANK_PAYMENT_TYPE => [ 45 'title' => __( 'Bank transfer (no payment required)', 'bookiflex' ), 46 'description' => __( 'Booking is confirmed immediately. Bank details are shared with the guest.', 'bookiflex' ), 47 ], 48 PaymentTypeInterface::BANK_PAYMENT_PAYABLE_TYPE => [ 49 'title' => __( 'Bank transfer (payment required)', 'bookiflex' ), 50 'description' => __( 'Booking is held until the guest completes the bank transfer within the allowed time.', 'bookiflex' ), 51 ], 52 PaymentTypeInterface::INTERNET_PAYMENT_TYPE => [ 53 'title' => __( 'Online payment', 'bookiflex' ), 54 'description' => __( 'Booking is held until the guest pays online via the selected payment gateway.', 'bookiflex' ), 55 ], 56 ], 57 PaymentTypeInterface::PAYMENT_ON_ARRIVAL_TYPE 58 ), 33 59 // Payment Gateway Settings 34 60 Field::make( 'separator', 'bflex_payment_gateway_separator', __( 'Payment Gateway Settings', 'bookiflex' ) )->set_conditional_logic( [[ … … 66 92 ] ); 67 93 $paymentSettingsFields = array_merge( $paymentSettingsFields, $this->addBasePaymentSettingsFields() ); 68 Container::make( 'post_meta', __( 'Configuration', 'bookiflex' ) )->where( 'post_type', '=', self::POST_TYPE )->add_ tab( __( 'Payment Method Settings', 'bookiflex' ),$paymentSettingsFields );94 Container::make( 'post_meta', __( 'Configuration', 'bookiflex' ) )->where( 'post_type', '=', self::POST_TYPE )->add_fields( $paymentSettingsFields ); 69 95 } 70 96 -
bookiflex/trunk/src/Admin/CPT/RatePlan.php
r3478607 r3495560 18 18 use BookiFlex\Core\Admin\CPT\PaymentType; 19 19 use BookiFlex\Core\Admin\CPT\RatePlan as BaseCPT; 20 use BookiFlex\Core\Admin\Field\SectionNotice; 20 21 use BookiFlex\Core\Contract\PluginInterface; 21 22 use BookiFlex\Core\Model\AccommodationType\AccommodationPlacementTypeInterface; … … 23 24 use BookiFlex\Core\Model\RatePlan\BoardTypeInterface; 24 25 use BookiFlex\Core\Util\ProFeature; 26 use BookiFlex\Core\Admin\Field\RadioCard; 25 27 use BookiFlex\Extensions\Onboarding\Contract\OnboardingPresetsProviderInterface; 26 28 use Carbon_Fields\Container; … … 35 37 public function register( PluginInterface $plugin ) : void { 36 38 parent::register( $plugin ); 39 $this->customizeMenuOrder( __( 'Display order', 'bookiflex' ), __( 'Controls the display order of this rate plan. Lower numbers appear first.', 'bookiflex' ) ); 40 if ( $this->supportInheritance() ) { 41 $this->customizeParentSelector( __( 'Parent rate plan', 'bookiflex' ), __( 'Select a parent rate plan to inherit prices and restrictions from.', 'bookiflex' ) ); 42 } 43 $this->customizeExcerpt( __( 'Description', 'bookiflex' ), __( 'A brief description of this rate plan. This text may be shown to guests during the booking process.', 'bookiflex' ) ); 37 44 $this->plugin->addAction( 38 45 'carbon_fields_post_meta_container_saved', … … 49 56 50 57 public function registerMetaBoxes() : void { 51 $generalFields = [ 52 Field::make( 'text', self::FIELD_SHORT_CODE, __( 'Short code', 'bookiflex' ) )->set_width( 50 )->set_attribute( 'maxLength', '10' )->set_attribute( 'readOnly', 'true' )->help_text( __( 'A short identifier for this rate plan (generated automatically). For example: BRP for Base rate plan, SAM for Summer vacation rate plan. This code may be used internally or in reports.', 'bookiflex' ) ), 53 Field::make( 'hidden', self::FIELD_BOARD_TYPE, '' )->set_default_value( BoardTypeInterface::ROOM_ONLY ), 54 Field::make( 'separator', 'bflex_rental_units_separator', __( 'Rental units', 'bookiflex' ) ), 55 Field::make( 'html', 'rental-units-html' )->set_html( sprintf( '<p>%s</p>', __( 'Select the rental units this rate plan applies to. You\'ll be able to define prices and restrictions for each one separately.', 'bookiflex' ) ) ), 56 Field::make( 'association', self::FIELD_ACCOMMODATION_TYPES, '' )->set_required()->set_types( [[ 57 'type' => 'post', 58 'post_type' => AccommodationType::POST_TYPE, 59 ]] ) 60 ]; 61 Container::make( 'post_meta', 'rate-plan-fields', __( 'Configuration', 'bookiflex' ) )->where( 'post_type', '=', self::POST_TYPE )->add_tab( __( 'General', 'bookiflex' ), $generalFields )->add_tab( __( 'Booking terms', 'bookiflex' ), $this->buildBookingTermsFields() ); 58 $generalFields = [Field::make( 'hidden', self::FIELD_BOARD_TYPE, '' )->set_default_value( BoardTypeInterface::ROOM_ONLY ), SectionNotice::make( 'bflex__rp__accommodation_types-html', sprintf( '<strong>%s</strong> %s', __( 'Select the rental units this rate plan applies to.', 'bookiflex' ), __( 'You\'ll be able to define prices and restrictions for each one separately.', 'bookiflex' ) ) ), Field::make( 'association', self::FIELD_ACCOMMODATION_TYPES, '' )->set_required()->set_types( [[ 59 'type' => 'post', 60 'post_type' => AccommodationType::POST_TYPE, 61 ]] )]; 62 Container::make( 'post_meta', 'rate-plan-short-code', __( 'Short code', 'bookiflex' ) )->where( 'post_type', '=', self::POST_TYPE )->set_context( 'side' )->add_fields( [Field::make( 'text', self::FIELD_SHORT_CODE, '' )->set_attribute( 'maxLength', '10' )->set_attribute( 'readOnly', 'true' )->help_text( __( 'A short identifier for this rate plan (generated automatically). For example: BRP for Base rate plan, SAM for Summer vacation rate plan. This code may be used internally or in reports.', 'bookiflex' ) )] ); 63 Container::make( 'post_meta', 'rate-plan-fields', __( 'Configuration', 'bookiflex' ) )->set_layout( 'tabbed-vertical' )->where( 'post_type', '=', self::POST_TYPE )->add_tab( __( 'General', 'bookiflex' ), $generalFields )->add_tab( __( 'Booking terms', 'bookiflex' ), $this->buildBookingTermsFields() ); 62 64 $this->showNotice(); 63 65 } … … 74 76 private function buildBookingTermsFields() : array { 75 77 $fields = []; 76 $fields[] = Field::make( 'html', 'booking-terms-html' )->set_html( sprintf( '<p>%s</p>', __( 'Choose how guests pay and what cancellation rules apply to this rate plan.', 'bookiflex' ) ) ); 77 $fields[] = Field::make( 'radio', self::FIELD_BOOKING_TERMS, '' )->set_options( function () { 78 return $this->getAvailableBookingTermsOptions(); 79 } )->set_default_value( $this->getDefaultBookingTermsValue() ); 80 // Add conditional description blocks for each preset 78 $fields[] = SectionNotice::make( 'booking-terms-html', __( 'Choose how guests pay and what cancellation rules apply to this rate plan.', 'bookiflex' ) ); 79 // Build RadioCard options from presets 80 $options = []; 81 81 $presets = $this->presetsProvider->getBookingPresets(); 82 82 foreach ( $presets as $preset ) { 83 $html = sprintf( '<div style="padding: 12px 16px; background: #f0f6fc; border-left: 4px solid #0073aa; margin: 8px 0;"> 84 <p style="margin: 0 0 6px;">%s</p> 85 <p style="margin: 0; color: #555; font-style: italic;">%s</p> 86 </div>', esc_html( $preset['shortDescription'] ), esc_html( $preset['recommendation'] ) ); 87 $fields[] = Field::make( 'html', 'preset_' . $preset['id'] . '_desc' )->set_html( $html )->set_conditional_logic( [[ 88 'field' => self::FIELD_BOOKING_TERMS, 89 'value' => $preset['id'], 90 ]] ); 91 } 92 // Custom description 93 $fields[] = Field::make( 'html', 'custom_booking_terms_desc' )->set_html( sprintf( '<div style="padding: 12px 16px; background: #fff8e5; border-left: 4px solid #dba617; margin: 8px 0;"> 94 <p style="margin: 0;">%s</p> 95 </div>', esc_html__( 'Manually select the payment method(s) and cancellation policy for this rate plan.', 'bookiflex' ) ) )->set_conditional_logic( [[ 83 $paymentTypeId = $this->findCptByPresetKey( PaymentType::POST_TYPE, $preset['paymentTypeKey'] ); 84 $cancellationPolicyId = $this->findCptByPresetKey( CancellationPolicy::POST_TYPE, $preset['cancellationPolicyKey'] ); 85 if ( $paymentTypeId && $cancellationPolicyId ) { 86 $title = $preset['title']; 87 if ( !empty( $preset['popular'] ) ) { 88 $title .= ' ' . __( '(recommended)', 'bookiflex' ); 89 } 90 $description = $preset['shortDescription']; 91 if ( !empty( $preset['recommendation'] ) ) { 92 $description .= ' ' . $preset['recommendation']; 93 } 94 $options[$preset['id']] = [ 95 'title' => $title, 96 'description' => $description, 97 ]; 98 } 99 } 100 $options['custom'] = [ 101 'title' => __( 'Custom', 'bookiflex' ), 102 'description' => __( 'Manually select the payment method(s) and cancellation policy for this rate plan.', 'bookiflex' ), 103 ]; 104 $default = $this->getDefaultBookingTermsValue(); 105 array_push( $fields, ...RadioCard::make( 106 self::FIELD_BOOKING_TERMS, 107 __( 'Booking terms', 'bookiflex' ), 108 $options, 109 $default, 110 true 111 ) ); 112 // Association fields — visible only for Custom 113 $fields[] = Field::make( 'separator', 'bflex__cp__strict_separator', __( 'Configuration', 'bookiflex' ) )->set_conditional_logic( [[ 96 114 'field' => self::FIELD_BOOKING_TERMS, 97 115 'value' => 'custom', 98 116 ]] ); 99 // Association fields — visible only for Custom100 117 $fields[] = Field::make( 'association', self::FIELD_PAYMENT_TYPES, __( 'Payment types', 'bookiflex' ) )->set_types( [[ 101 118 'type' => 'post', … … 116 133 117 134 /** 118 * Get available booking terms options for radio field. 119 * 120 * Only includes presets for which both PaymentType and CancellationPolicy CPTs 121 * with matching `_bflex_preset_key` exist in the database. 122 * 123 * @return array<string, string> 124 */ 125 private function getAvailableBookingTermsOptions() : array { 135 * Get default value for booking terms radio. 136 * 137 * Returns the first available preset id, or 'custom' if none available. 138 * 139 * @return string 140 */ 141 private function getDefaultBookingTermsValue() : string { 126 142 $presets = $this->presetsProvider->getBookingPresets(); 127 $options = [];128 143 foreach ( $presets as $preset ) { 129 144 $paymentTypeId = $this->findCptByPresetKey( PaymentType::POST_TYPE, $preset['paymentTypeKey'] ); 130 145 $cancellationPolicyId = $this->findCptByPresetKey( CancellationPolicy::POST_TYPE, $preset['cancellationPolicyKey'] ); 131 146 if ( $paymentTypeId && $cancellationPolicyId ) { 132 $label = $preset['title']; 133 if ( !empty( $preset['popular'] ) ) { 134 $label .= ' ' . __( '(recommended)', 'bookiflex' ); 135 } 136 $options[$preset['id']] = $label; 137 } 138 } 139 $options['custom'] = __( 'Custom', 'bookiflex' ); 140 return $options; 141 } 142 143 /** 144 * Get default value for booking terms radio. 145 * 146 * Returns the first available preset id, or 'custom' if none available. 147 * 148 * @return string 149 */ 150 private function getDefaultBookingTermsValue() : string { 151 $options = $this->getAvailableBookingTermsOptions(); 152 $keys = array_keys( $options ); 153 // Return first non-custom option, or 'custom' 154 foreach ( $keys as $key ) { 155 if ( $key !== 'custom' ) { 156 return $key; 147 return $preset['id']; 157 148 } 158 149 } -
bookiflex/trunk/src/Core/Admin/CPT/AbstractCPT.php
r3478607 r3495560 43 43 $query->set('order', 'ASC'); 44 44 } 45 } 46 47 protected function customizeMenuOrder(string $title, string $description): void 48 { 49 $this->plugin->addAction('add_meta_boxes', function () use ($title, $description) { 50 add_meta_box( 51 'bflex_' . static::POST_TYPE . '_menu_order', 52 $title, 53 function ($post) use ($description) { 54 echo '<input name="menu_order" type="number" min="0" id="menu_order" value="' . esc_attr($post->menu_order) . '" style="width:100%" />'; 55 echo '<p class="description">' . esc_html($description) . '</p>'; 56 }, 57 static::POST_TYPE, 58 'side' 59 ); 60 }); 61 } 62 63 protected function customizeParentSelector(string $title, string $description): void 64 { 65 $this->plugin->addAction('add_meta_boxes', function () use ($title, $description) { 66 add_meta_box( 67 'bflex_' . static::POST_TYPE . '_parent', 68 $title, 69 function ($post) use ($description) { 70 $dropdown = wp_dropdown_pages([ 71 'post_type' => $post->post_type, 72 'exclude_tree' => $post->ID, 73 'selected' => $post->post_parent, 74 'name' => 'parent_id', 75 'show_option_none' => __('(no parent)', 'bookiflex'), 76 'sort_column' => 'menu_order, post_title', 77 'echo' => 0, 78 ]); 79 if ($dropdown) { 80 echo $dropdown; 81 } 82 echo '<p class="description">' . esc_html($description) . '</p>'; 83 }, 84 static::POST_TYPE, 85 'side' 86 ); 87 }); 88 } 89 90 protected function customizeExcerpt(string $title, string $description): void 91 { 92 $this->plugin->addAction('add_meta_boxes', function () use ($title, $description) { 93 add_meta_box( 94 'bflex_' . static::POST_TYPE . '_excerpt', 95 $title, 96 function ($post) use ($title, $description) { 97 ?> 98 <label class="screen-reader-text" for="excerpt"><?php echo esc_html($title); ?></label> 99 <textarea rows="1" cols="40" name="excerpt" id="excerpt"><?php echo esc_html($post->post_excerpt); ?></textarea> 100 <p><?php echo esc_html($description); ?></p> 101 <?php 102 }, 103 static::POST_TYPE, 104 'normal' 105 ); 106 }); 45 107 } 46 108 -
bookiflex/trunk/src/Core/Admin/CPT/AccommodationType.php
r3478607 r3495560 56 56 // Register event hooks from trait 57 57 $this->registerEventHooks(); 58 59 // Thumbnail column in list table 60 $this->plugin->addFilter('manage_' . self::POST_TYPE . '_posts_columns', [$this, 'addThumbnailColumn']); 61 $this->plugin->addAction('manage_' . self::POST_TYPE . '_posts_custom_column', [$this, 'renderThumbnailColumn'], 10, 2); 62 } 63 64 /** 65 * Insert "Image" column before "title" 66 */ 67 public function addThumbnailColumn(array $columns): array 68 { 69 $result = []; 70 71 foreach ($columns as $key => $label) { 72 if ($key === 'title') { 73 $result['bflex_thumbnail'] = __('Image', 'bookiflex'); 74 } 75 $result[$key] = $label; 76 } 77 78 return $result; 79 } 80 81 /** 82 * Render thumbnail or placeholder in list column 83 */ 84 public function renderThumbnailColumn(string $column, int $postId): void 85 { 86 if ($column !== 'bflex_thumbnail') { 87 return; 88 } 89 90 if (has_post_thumbnail($postId)) { 91 echo get_the_post_thumbnail($postId, [80, 80]); 92 } else { 93 echo '<span class="bflex-thumbnail-placeholder dashicons dashicons-format-image"></span>'; 94 } 58 95 } 59 96 … … 99 136 'hierarchical' => false, 100 137 'menu_position' => 0, 101 'supports' => ['title', ' excerpt', 'thumbnail', 'page-attributes'],138 'supports' => ['title', 'thumbnail'], 102 139 'capability_type' => self::POST_TYPE, 103 140 'capabilities' => [ -
bookiflex/trunk/src/Core/Admin/CPT/CancellationPolicy.php
r3478607 r3495560 16 16 namespace BookiFlex\Core\Admin\CPT; 17 17 18 use BookiFlex\Core\Contract\PluginInterface; 18 19 use BookiFlex\Core\Contract\RoleCapabilitiesInterface; 19 20 … … 43 44 public const FIELD_STRICT_TIME_WINDOW = 'bflex__cp__strict_time_window'; 44 45 public const FIELD_STRICT_PENALTY_PERCENT = 'bflex__cp__strict_penalty_percent'; 46 47 public function register(PluginInterface $plugin): void 48 { 49 parent::register($plugin); 50 51 $this->customizeExcerpt( 52 __('Description', 'bookiflex'), 53 __('An optional note for your own reference. This text is not shown to guests.', 'bookiflex') 54 ); 55 } 45 56 46 57 public function registerPostType(): void … … 80 91 'hierarchical' => false, 81 92 'menu_position' => 2, 82 'supports' => ['title' , 'excerpt'],93 'supports' => ['title'], 83 94 'capability_type' => self::POST_TYPE, 84 95 'capabilities' => [ -
bookiflex/trunk/src/Core/Admin/CPT/PaymentType.php
r3478607 r3495560 78 78 'hierarchical' => false, 79 79 'menu_position' => 3, 80 'supports' => ['title' , 'excerpt'],80 'supports' => ['title'], 81 81 'capability_type' => self::POST_TYPE, 82 82 'capabilities' => [ -
bookiflex/trunk/src/Core/Admin/CPT/RatePlan.php
r3478607 r3495560 85 85 'hierarchical' => $this->supportInheritance(), 86 86 'menu_position' => 1, 87 'supports' => ['title' , 'excerpt', 'page-attributes'],87 'supports' => ['title'], 88 88 'capability_type' => self::POST_TYPE, 89 89 'capabilities' => [ -
bookiflex/trunk/vendor/composer/autoload_classmap.php
r3478614 r3495560 24 24 'BookiFlex\\Core\\Admin\\CTL\\CustomerTableList' => $baseDir . '/src/Core/Admin/CTL/CustomerTableList.php', 25 25 'BookiFlex\\Core\\Admin\\CTL\\ReservationTableList' => $baseDir . '/src/Core/Admin/CTL/ReservationTableList.php', 26 'BookiFlex\\Core\\Admin\\Field\\RadioCard' => $baseDir . '/src/Core/Admin/Field/RadioCard.php', 27 'BookiFlex\\Core\\Admin\\Field\\SectionNotice' => $baseDir . '/src/Core/Admin/Field/SectionNotice.php', 26 28 'BookiFlex\\Core\\Admin\\Lifecycle\\AbstractExtensionActivator' => $baseDir . '/src/Core/Admin/Lifecycle/AbstractExtensionActivator.php', 27 29 'BookiFlex\\Core\\Admin\\Lifecycle\\AbstractUninstaller' => $baseDir . '/src/Core/Admin/Lifecycle/AbstractUninstaller.php', -
bookiflex/trunk/vendor/composer/autoload_static.php
r3483810 r3495560 456 456 'BookiFlex\\Core\\Admin\\CTL\\CustomerTableList' => __DIR__ . '/../..' . '/src/Core/Admin/CTL/CustomerTableList.php', 457 457 'BookiFlex\\Core\\Admin\\CTL\\ReservationTableList' => __DIR__ . '/../..' . '/src/Core/Admin/CTL/ReservationTableList.php', 458 'BookiFlex\\Core\\Admin\\Field\\RadioCard' => __DIR__ . '/../..' . '/src/Core/Admin/Field/RadioCard.php', 459 'BookiFlex\\Core\\Admin\\Field\\SectionNotice' => __DIR__ . '/../..' . '/src/Core/Admin/Field/SectionNotice.php', 458 460 'BookiFlex\\Core\\Admin\\Lifecycle\\AbstractExtensionActivator' => __DIR__ . '/../..' . '/src/Core/Admin/Lifecycle/AbstractExtensionActivator.php', 459 461 'BookiFlex\\Core\\Admin\\Lifecycle\\AbstractUninstaller' => __DIR__ . '/../..' . '/src/Core/Admin/Lifecycle/AbstractUninstaller.php', -
bookiflex/trunk/vendor/composer/installed.php
r3493377 r3495560 2 2 'root' => array( 3 3 'name' => 'bookiflex/plugin', 4 'pretty_version' => 'v1. 1.1',5 'version' => '1. 1.1.0',6 'reference' => ' 198f1b412b1060aca0e245573237bc45105d1d82',4 'pretty_version' => 'v1.2.0', 5 'version' => '1.2.0.0', 6 'reference' => 'b01ef3c27da8b2bf4bde963764fcc52c71eeb6db', 7 7 'type' => 'wordpress-plugin', 8 8 'install_path' => __DIR__ . '/../../', … … 21 21 ), 22 22 'bookiflex/plugin' => array( 23 'pretty_version' => 'v1. 1.1',24 'version' => '1. 1.1.0',25 'reference' => ' 198f1b412b1060aca0e245573237bc45105d1d82',23 'pretty_version' => 'v1.2.0', 24 'version' => '1.2.0.0', 25 'reference' => 'b01ef3c27da8b2bf4bde963764fcc52c71eeb6db', 26 26 'type' => 'wordpress-plugin', 27 27 'install_path' => __DIR__ . '/../../',
Note: See TracChangeset
for help on using the changeset viewer.