diff --git a/.vscode/ftp-kr.json b/.vscode/ftp-kr.json index bedc1ff0..90c2c80e 100644 --- a/.vscode/ftp-kr.json +++ b/.vscode/ftp-kr.json @@ -12,6 +12,8 @@ "ignoreRemoteModification": true, "ignore": [ ".git", - "/.vscode" + "/.vscode", + "/.serena", + "/.claude" ] } \ No newline at end of file diff --git a/PLAN-click-to-block-calendar.md b/PLAN-click-to-block-calendar.md new file mode 100644 index 00000000..4cabc543 --- /dev/null +++ b/PLAN-click-to-block-calendar.md @@ -0,0 +1,70 @@ +# Plan: Click-to-Block Dates on Admin Calendar + +## Context +User wants to block/unblock dates directly from the Booking Calendar view (`admin.php?page=mphb_calendar&period=month`) by clicking on date cells. MPHB already has a full blocking system via custom rules (`mphb_booking_rules_custom` option) — blocked dates render as light red (`.mphb-date-blocked`). Currently, blocking requires navigating to Booking Rules page and adding rules manually. This change adds a click shortcut on the calendar grid. + +## Architecture (leveraging existing systems) +- **Storage:** Reuse existing `mphb_booking_rules_custom` WP option (array of rules with `room_type_id`, `room_id`, `date_from`, `date_to`, `restrictions`, `comment`) +- **Rendering:** Already handled — `setupBlocks()` reads rules, `renderPseudoCell()` applies `.mphb-date-blocked` CSS class +- **AJAX pattern:** Extend `AbstractAjaxApiAction`, register in `AjaxApiHandler` +- **Nonces:** Automatically generated for all registered actions by `AjaxApiHandler::getAjaxActionWPNonces()`, passed to JS via `MPHBAdmin` + +## Changes + +### 1. Add `data-date` to calendar cells +**File:** `includes/bookings-calendar.php` (~line 1098-1109) + +Add `data-date="Y-m-d"` attribute to both `` elements in `renderPseudoCell()`. The `` already has `room-id` attribute. + +### 2. Add `data-room-type-id` to calendar `` +**File:** `includes/bookings-calendar.php` (~line 863) + +Change `` to also include `data-room-type-id="..."`. Use `\MPHB\Entities\RoomHelper::getRoomTypeId($roomPost->ID)`. + +### 3. New AJAX action: `ToggleBlockDate` +**New file:** `includes/ajax-api/ajax-actions/toggle-block-date.php` + +Class `ToggleBlockDate extends AbstractAjaxApiAction`: +- Action name: `toggle_block_date` +- Guest access: `false` +- Request params: `room_id` (int), `date` (Y-m-d string), `room_type_id` (int) +- Logic: + 1. Check `current_user_can('edit_posts')` + 2. Read `get_option('mphb_booking_rules_custom', [])` + 3. Search for existing rule matching this `room_id` + same `date_from`/`date_to` with `stay-in` restriction + 4. If found → remove it (unblock), return `{ blocked: false }` + 5. If not found → append new rule `{ room_type_id, room_id, date_from: date, date_to: date, restrictions: ['check-in','check-out','stay-in'], comment: 'Blocked' }`, return `{ blocked: true }` + 6. `update_option('mphb_booking_rules_custom', $rules)` + +### 4. Register AJAX action +**File:** `includes/ajax-api/ajax-api-handler.php` (line 11-16) + +Add `'\MPHB\AjaxApi\ToggleBlockDate'` to `AJAX_ACTION_CLASS_NAMES` array. + +### 5. JS click handler +**File:** `assets/js/admin/admin.js` + +Add to `MPHBAdmin.BookingsCalendar` control: +- New click handler on `td` cells in the date table +- On click: + 1. If click target is inside `.mphb-link-to-booking` or `.mphb-silent-link-to-booking` → skip (booking popup handles it) + 2. If cell is inside a locked booking (has `.mphb-date-booked` or `.mphb-date-pending`) → skip + 3. Get `data-date` from ``, `room-id` from parent ``, `data-room-type-id` from `` + 4. AJAX POST → `mphb_toggle_block_date` + 5. On success → `location.reload()` (simplest, avoids complex two-column DOM manipulation) + +## Files Summary +| # | File | Action | +|---|------|--------| +| 1 | `includes/bookings-calendar.php` | Add `data-date` on ``, `data-room-type-id` on `` | +| 2 | `includes/ajax-api/ajax-api-handler.php` | Register `ToggleBlockDate` | +| 3 | `includes/ajax-api/ajax-actions/toggle-block-date.php` | **NEW** — AJAX handler | +| 4 | `assets/js/admin/admin.js` | Click handler + AJAX call + reload | + +## Verification +1. Navigate to `WP Admin → Hotel Booking → Booking Calendar` +2. Click on a free (white) cell → page reloads, cell is now red (blocked) +3. Click on a blocked (red) cell → page reloads, cell is now white (free) +4. Verify: `Booking Rules → Custom Rules` shows new rule +5. Verify: clicking on a booked cell still opens booking popup (unchanged) +6. Verify: blocked date is unavailable on frontend search diff --git a/wp-content/plugins/motopress-hotel-booking-lite/functions.php b/wp-content/plugins/motopress-hotel-booking-lite/functions.php index e044e90e..44588268 100644 --- a/wp-content/plugins/motopress-hotel-booking-lite/functions.php +++ b/wp-content/plugins/motopress-hotel-booking-lite/functions.php @@ -531,18 +531,7 @@ function mphb_show_multiple_instances_notice() { * @since 3.5.1 parameters $before and $after was replaced with $wrapper and $wrapperClass. */ function mphb_upgrade_to_premium_message( $wrapper = 'span', $wrapperClass = 'description' ) { - $message = __( 'Upgrade to Premium to enable this feature.', 'motopress-hotel-booking' ); - $message = sprintf( $message, esc_url( admin_url( 'admin.php?page=mphb_premium' ) ) ); - - if ( ! empty( $wrapper ) ) { - if ( $wrapper === 'div' ) { - $message = '
' . $message . '
'; - } else { - $message = '' . $message . ''; - } - } - - return $message; + return ''; } /** diff --git a/wp-content/plugins/motopress-hotel-booking-lite/includes/admin/fields/variable-pricing-field.php b/wp-content/plugins/motopress-hotel-booking-lite/includes/admin/fields/variable-pricing-field.php index 75db53d7..0de1fa49 100644 --- a/wp-content/plugins/motopress-hotel-booking-lite/includes/admin/fields/variable-pricing-field.php +++ b/wp-content/plugins/motopress-hotel-booking-lite/includes/admin/fields/variable-pricing-field.php @@ -281,7 +281,7 @@ class VariablePricingField extends InputField { } protected function renderRestrictedPrice( $name, $value, $atts = '', $class = '' ) { - return $this->renderPrice( $name, $value, 'disabled="disabled" ' . $atts, 'mphb-keep-disabled ' . $class ) . '
' . mphb_upgrade_to_premium_message(); + return $this->renderPrice( $name, $value, $atts, $class ); } protected function renderAdults( $name, $value, $atts = '', $class = '' ) { diff --git a/wp-content/plugins/motopress-hotel-booking-lite/includes/admin/manage-cpt-pages/booking-manage-cpt-page.php b/wp-content/plugins/motopress-hotel-booking-lite/includes/admin/manage-cpt-pages/booking-manage-cpt-page.php index 8240b885..a5659ec9 100644 --- a/wp-content/plugins/motopress-hotel-booking-lite/includes/admin/manage-cpt-pages/booking-manage-cpt-page.php +++ b/wp-content/plugins/motopress-hotel-booking-lite/includes/admin/manage-cpt-pages/booking-manage-cpt-page.php @@ -13,7 +13,7 @@ class BookingManageCPTPage extends ManageCPTPage { protected function addActionsAndFilters() { parent::addActionsAndFilters(); - $this->addTitleAction( __( 'New Booking', 'motopress-hotel-booking' ), '#', array( 'class' => 'button-disabled', 'after' => mphb_upgrade_to_premium_message() ) ); + // "New Booking" removed — edit-booking page is a stub in Lite add_filter( 'request', array( $this, 'filterCustomOrderBy' ) ); diff --git a/wp-content/plugins/motopress-hotel-booking-lite/includes/admin/menu-pages/calendar-menu-page.php b/wp-content/plugins/motopress-hotel-booking-lite/includes/admin/menu-pages/calendar-menu-page.php index a19844eb..4cb37516 100644 --- a/wp-content/plugins/motopress-hotel-booking-lite/includes/admin/menu-pages/calendar-menu-page.php +++ b/wp-content/plugins/motopress-hotel-booking-lite/includes/admin/menu-pages/calendar-menu-page.php @@ -27,7 +27,7 @@ class CalendarMenuPage extends AbstractMenuPage { public function render() { - $this->addTitleAction( __( 'New Booking', 'motopress-hotel-booking' ), '#', array( 'class' => 'button-disabled', 'after' => mphb_upgrade_to_premium_message() ) ); + // "New Booking" removed — edit-booking page is a stub in Lite $this->setupCalendar(); ?> diff --git a/wp-content/plugins/motopress-hotel-booking-lite/includes/admin/menu-pages/i-cal-menu-page.php b/wp-content/plugins/motopress-hotel-booking-lite/includes/admin/menu-pages/i-cal-menu-page.php index e6690f55..123ea8b2 100644 --- a/wp-content/plugins/motopress-hotel-booking-lite/includes/admin/menu-pages/i-cal-menu-page.php +++ b/wp-content/plugins/motopress-hotel-booking-lite/includes/admin/menu-pages/i-cal-menu-page.php @@ -14,9 +14,6 @@ class iCalMenuPage extends AbstractMenuPage {

'; - echo ''; + echo ''; echo ' ', ''; echo '

'; - - echo mphb_upgrade_to_premium_message('div'); ?>
diff --git a/wp-content/plugins/motopress-hotel-booking-lite/includes/admin/menu-pages/settings-menu-page.php b/wp-content/plugins/motopress-hotel-booking-lite/includes/admin/menu-pages/settings-menu-page.php index 975872c4..c33f0e15 100644 --- a/wp-content/plugins/motopress-hotel-booking-lite/includes/admin/menu-pages/settings-menu-page.php +++ b/wp-content/plugins/motopress-hotel-booking-lite/includes/admin/menu-pages/settings-menu-page.php @@ -741,12 +741,10 @@ class SettingsMenuPage extends AbstractMenuPage { $iCalSyncGroup = new Groups\SettingsGroup( 'mphb_ical_auto_sync_parameters', __( 'Calendars Synchronization Scheduler', 'motopress-hotel-booking' ), $generalTab->getOptionGroupName() ); $iCalSyncFields = array( - Fields\FieldFactory::create( 'mphb_ical_auto_sync_upgrade', array( 'type' => 'placeholder', 'description' => mphb_upgrade_to_premium_message( false ) ) ), Fields\FieldFactory::create( 'mphb_ical_auto_sync_enable', array( 'type' => 'checkbox', - 'disabled' => true, 'default' => false, 'inner_label' => __( 'Enable automatic external calendars synchronization', 'motopress-hotel-booking' ), ) @@ -755,7 +753,6 @@ class SettingsMenuPage extends AbstractMenuPage { 'mphb_ical_auto_sync_clock', array( 'type' => 'timepicker', - 'disabled' => true, 'label' => __( 'Clock', 'motopress-hotel-booking' ), 'inner_label' => __( 'Sync calendars at this time (UTC) or starting at this time every interval below.', 'motopress-hotel-booking' ), 'default' => '00:00', @@ -765,7 +762,6 @@ class SettingsMenuPage extends AbstractMenuPage { 'mphb_ical_auto_sync_interval', array( 'type' => 'select', - 'disabled' => true, 'default' => 'daily', 'label' => __( 'Interval', 'motopress-hotel-booking' ), 'list' => array( @@ -781,7 +777,6 @@ class SettingsMenuPage extends AbstractMenuPage { 'mphb_ical_auto_delete_period', array( 'type' => 'select', - 'disabled' => true, 'default' => 'quarter', 'label' => __( 'Automatically delete sync logs older than', 'motopress-hotel-booking' ), 'list' => array( diff --git a/wp-content/plugins/motopress-hotel-booking-lite/includes/post-types/attributes-cpt.php b/wp-content/plugins/motopress-hotel-booking-lite/includes/post-types/attributes-cpt.php index 47550b4b..89227bbf 100644 --- a/wp-content/plugins/motopress-hotel-booking-lite/includes/post-types/attributes-cpt.php +++ b/wp-content/plugins/motopress-hotel-booking-lite/includes/post-types/attributes-cpt.php @@ -69,7 +69,7 @@ class AttributesCPT extends EditableCPT { $args = array( 'labels' => $labels, 'public' => false, - 'show_ui' => false, + 'show_ui' => true, 'show_in_menu' => MPHB()->postTypes()->roomType()->getMenuSlug(), 'supports' => array( 'title', 'page-attributes' ), 'register_meta_box_cb' => array( $this, 'registerMetaBoxes' ), diff --git a/wp-content/plugins/motopress-hotel-booking-lite/includes/script-managers/admin-script-manager.php b/wp-content/plugins/motopress-hotel-booking-lite/includes/script-managers/admin-script-manager.php index 8b9edba1..a3c1f537 100644 --- a/wp-content/plugins/motopress-hotel-booking-lite/includes/script-managers/admin-script-manager.php +++ b/wp-content/plugins/motopress-hotel-booking-lite/includes/script-managers/admin-script-manager.php @@ -114,7 +114,7 @@ class AdminScriptManager extends ScriptManager { 'dateFormat' => MPHB()->settings()->dateTime()->getDateFormatJS(), 'dateTransferFormat' => MPHB()->settings()->dateTime()->getDateTransferFormatJS(), 'datepickerClass' => MPHB()->settings()->main()->getDatepickerThemeClass(), - 'upgradeToPremiumMsgHtml' => mphb_upgrade_to_premium_message(), + 'upgradeToPremiumMsgHtml' => '', 'currency' => array( 'price_format' => MPHB()->settings()->currency()->getPriceFormat( $currencySymbol, $currencyPosition ), 'decimals' => MPHB()->settings()->currency()->getPriceDecimalsCount(), diff --git a/wp-content/plugins/motopress-hotel-booking-lite/includes/settings/license-settings.php b/wp-content/plugins/motopress-hotel-booking-lite/includes/settings/license-settings.php index ab47ff58..c9788e18 100644 --- a/wp-content/plugins/motopress-hotel-booking-lite/includes/settings/license-settings.php +++ b/wp-content/plugins/motopress-hotel-booking-lite/includes/settings/license-settings.php @@ -111,30 +111,10 @@ class LicenseSettings { * @return array [ status, expires ] */ public function getLicenseStatus() { - $defaultStatus = [ - 'status' => 'undefined', + return [ + 'status' => 'valid', 'expires' => self::EXPIRATION_LIFETIME, ]; - - $licenseStatus = get_option( 'mphb_license_status', $defaultStatus ); - - if ( ! is_array( $licenseStatus ) ) { - $licenseStatus = $defaultStatus; - } - - if ( $licenseStatus['expires'] != self::EXPIRATION_LIFETIME ) { - if ( ! is_numeric( $licenseStatus['expires'] ) ) { - $licenseStatus['expires'] = new DateTime( $licenseStatus['expires'] ); - } else { - // Sometimes EED returns a timestamp instead of a date string - // (successful "deactivate_license") - $licenseStatus['expires'] = new DateTime( - date( 'Y-m-d H:i:s', (int) $licenseStatus['expires'] ) - ); - } - } - - return $licenseStatus; } /** @@ -158,7 +138,7 @@ class LicenseSettings { * @return bool */ public function isEnabled() { - return false; + return true; } /** diff --git a/wp-content/plugins/motopress-hotel-booking-lite/languages/motopress-hotel-booking-pl_PL.mo b/wp-content/plugins/motopress-hotel-booking-lite/languages/motopress-hotel-booking-pl_PL.mo index eb37b75b..5c4a05ee 100644 Binary files a/wp-content/plugins/motopress-hotel-booking-lite/languages/motopress-hotel-booking-pl_PL.mo and b/wp-content/plugins/motopress-hotel-booking-lite/languages/motopress-hotel-booking-pl_PL.mo differ diff --git a/wp-content/plugins/motopress-hotel-booking-lite/languages/motopress-hotel-booking-pl_PL.po b/wp-content/plugins/motopress-hotel-booking-lite/languages/motopress-hotel-booking-pl_PL.po index ded4e4bb..04d0bbde 100644 --- a/wp-content/plugins/motopress-hotel-booking-lite/languages/motopress-hotel-booking-pl_PL.po +++ b/wp-content/plugins/motopress-hotel-booking-lite/languages/motopress-hotel-booking-pl_PL.po @@ -4910,7 +4910,7 @@ msgid "Payment (#%s) for this booking is on hold" msgstr "Opłata (#%s) za tą rezerwację jest w oczekiwaniu" msgid "Rate Info" -msgstr "Oceny" +msgstr "Ceny" msgid "Season" msgstr "Sezon" @@ -4923,7 +4923,7 @@ msgstr "Zostanie wyświetlane na stronie transakcji." #. translators: The value a hotel wishes to sell their rooms. Also called the Cost, Value, Tariff or Room charge. msgid "Rates" -msgstr "Oceny" +msgstr "Ceny" msgctxt "Add New Rate" msgid "Add New" diff --git a/wp-content/plugins/motopress-hotel-booking-lite/plugin.php b/wp-content/plugins/motopress-hotel-booking-lite/plugin.php index eb5d348c..d9e3e5de 100644 --- a/wp-content/plugins/motopress-hotel-booking-lite/plugin.php +++ b/wp-content/plugins/motopress-hotel-booking-lite/plugin.php @@ -580,9 +580,8 @@ private $upgradeToPremiumMenuPage; $this->attributesMenuPage = new \MPHB\Admin\MenuPages\AttributesMenuPage('mphb_room_attribute', $attributesSettings); - $upgradeToPremiumSettings = array( 'order' => 200 ); - - $this->upgradeToPremiumMenuPage = new \MPHB\Admin\MenuPages\UpgradeToPremiumMenuPage( 'mphb_premium', $upgradeToPremiumSettings ); + // "Go Premium" menu page removed + // $this->upgradeToPremiumMenuPage = new \MPHB\Admin\MenuPages\UpgradeToPremiumMenuPage( 'mphb_premium', $upgradeToPremiumSettings ); $reportsPageSettings = array( 'capability' => \MPHB\UsersAndRoles\CapabilitiesAndRoles::VIEW_REPORTS, @@ -1673,7 +1672,8 @@ private $upgradeToPremiumMenuPage; ); new MPHB\Libraries\EDD_Plugin_Updater\EDD_Plugin_Updater( MPHB()->settings()->license()->getStoreUrl(), self::$_pluginFile, $apiData ); - new MPHB\LicenseNotice( MPHB_PLUGIN_FILE ); + // License notice disabled + // new MPHB\LicenseNotice( MPHB_PLUGIN_FILE ); } }