Remove premium upgrade messages and related functionality; add click-to-block dates feature in admin calendar

This commit is contained in:
2026-02-25 15:19:40 +01:00
parent 8c1b549770
commit 2bca262769
15 changed files with 89 additions and 58 deletions

4
.vscode/ftp-kr.json vendored
View File

@@ -12,6 +12,8 @@
"ignoreRemoteModification": true, "ignoreRemoteModification": true,
"ignore": [ "ignore": [
".git", ".git",
"/.vscode" "/.vscode",
"/.serena",
"/.claude"
] ]
} }

View File

@@ -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 `<td>` elements in `renderPseudoCell()`. The `<tr>` already has `room-id` attribute.
### 2. Add `data-room-type-id` to calendar `<tr>`
**File:** `includes/bookings-calendar.php` (~line 863)
Change `<tr room-id="...">` 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 `<td>`, `room-id` from parent `<tr>`, `data-room-type-id` from `<tr>`
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 `<td>`, `data-room-type-id` on `<tr>` |
| 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

View File

@@ -531,18 +531,7 @@ function mphb_show_multiple_instances_notice() {
* @since 3.5.1 parameters $before and $after was replaced with $wrapper and $wrapperClass. * @since 3.5.1 parameters $before and $after was replaced with $wrapper and $wrapperClass.
*/ */
function mphb_upgrade_to_premium_message( $wrapper = 'span', $wrapperClass = 'description' ) { function mphb_upgrade_to_premium_message( $wrapper = 'span', $wrapperClass = 'description' ) {
$message = __( '<a href="%s">Upgrade to Premium</a> to enable this feature.', 'motopress-hotel-booking' ); return '';
$message = sprintf( $message, esc_url( admin_url( 'admin.php?page=mphb_premium' ) ) );
if ( ! empty( $wrapper ) ) {
if ( $wrapper === 'div' ) {
$message = '<div class="' . esc_attr( $wrapperClass ) . '">' . $message . '</div>';
} else {
$message = '<span class="' . esc_attr( $wrapperClass ) . '">' . $message . '</span>';
}
}
return $message;
} }
/** /**

View File

@@ -281,7 +281,7 @@ class VariablePricingField extends InputField {
} }
protected function renderRestrictedPrice( $name, $value, $atts = '', $class = '' ) { protected function renderRestrictedPrice( $name, $value, $atts = '', $class = '' ) {
return $this->renderPrice( $name, $value, 'disabled="disabled" ' . $atts, 'mphb-keep-disabled ' . $class ) . '<br />' . mphb_upgrade_to_premium_message(); return $this->renderPrice( $name, $value, $atts, $class );
} }
protected function renderAdults( $name, $value, $atts = '', $class = '' ) { protected function renderAdults( $name, $value, $atts = '', $class = '' ) {

View File

@@ -13,7 +13,7 @@ class BookingManageCPTPage extends ManageCPTPage {
protected function addActionsAndFilters() { protected function addActionsAndFilters() {
parent::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' ) ); add_filter( 'request', array( $this, 'filterCustomOrderBy' ) );

View File

@@ -27,7 +27,7 @@ class CalendarMenuPage extends AbstractMenuPage {
public function render() { 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(); $this->setupCalendar();
?> ?>

View File

@@ -14,9 +14,6 @@ class iCalMenuPage extends AbstractMenuPage {
<p><?php esc_html_e( 'Sync your bookings across all online channels like Booking.com, TripAdvisor, Airbnb etc. via iCalendar file format.', 'motopress-hotel-booking' ); ?></p> <p><?php esc_html_e( 'Sync your bookings across all online channels like Booking.com, TripAdvisor, Airbnb etc. via iCalendar file format.', 'motopress-hotel-booking' ); ?></p>
<?php <?php
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo mphb_upgrade_to_premium_message( 'div' );
?> ?>
</div> </div>
<?php <?php

View File

@@ -181,12 +181,10 @@ class ReportsMenuPage extends AbstractMenuPage {
<?php <?php
echo '<p>'; echo '<p>';
echo '<button class="submit-button button button-secondary" disabled="disabled">', __('Generate CSV', 'motopress-hotel-booking'), '</button>'; echo '<button class="submit-button button button-secondary">', __('Generate CSV', 'motopress-hotel-booking'), '</button>';
echo ' ', '<span class="mphb-preloader mphb-hide"></span>'; echo ' ', '<span class="mphb-preloader mphb-hide"></span>';
echo '</p>'; echo '</p>';
echo mphb_upgrade_to_premium_message('div');
?> ?>
<div class="mphb-progress mphb-hide"> <div class="mphb-progress mphb-hide">

View File

@@ -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() ); $iCalSyncGroup = new Groups\SettingsGroup( 'mphb_ical_auto_sync_parameters', __( 'Calendars Synchronization Scheduler', 'motopress-hotel-booking' ), $generalTab->getOptionGroupName() );
$iCalSyncFields = array( $iCalSyncFields = array(
Fields\FieldFactory::create( 'mphb_ical_auto_sync_upgrade', array( 'type' => 'placeholder', 'description' => mphb_upgrade_to_premium_message( false ) ) ),
Fields\FieldFactory::create( Fields\FieldFactory::create(
'mphb_ical_auto_sync_enable', 'mphb_ical_auto_sync_enable',
array( array(
'type' => 'checkbox', 'type' => 'checkbox',
'disabled' => true,
'default' => false, 'default' => false,
'inner_label' => __( 'Enable automatic external calendars synchronization', 'motopress-hotel-booking' ), 'inner_label' => __( 'Enable automatic external calendars synchronization', 'motopress-hotel-booking' ),
) )
@@ -755,7 +753,6 @@ class SettingsMenuPage extends AbstractMenuPage {
'mphb_ical_auto_sync_clock', 'mphb_ical_auto_sync_clock',
array( array(
'type' => 'timepicker', 'type' => 'timepicker',
'disabled' => true,
'label' => __( 'Clock', 'motopress-hotel-booking' ), 'label' => __( 'Clock', 'motopress-hotel-booking' ),
'inner_label' => __( 'Sync calendars at this time (UTC) or starting at this time every interval below.', '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', 'default' => '00:00',
@@ -765,7 +762,6 @@ class SettingsMenuPage extends AbstractMenuPage {
'mphb_ical_auto_sync_interval', 'mphb_ical_auto_sync_interval',
array( array(
'type' => 'select', 'type' => 'select',
'disabled' => true,
'default' => 'daily', 'default' => 'daily',
'label' => __( 'Interval', 'motopress-hotel-booking' ), 'label' => __( 'Interval', 'motopress-hotel-booking' ),
'list' => array( 'list' => array(
@@ -781,7 +777,6 @@ class SettingsMenuPage extends AbstractMenuPage {
'mphb_ical_auto_delete_period', 'mphb_ical_auto_delete_period',
array( array(
'type' => 'select', 'type' => 'select',
'disabled' => true,
'default' => 'quarter', 'default' => 'quarter',
'label' => __( 'Automatically delete sync logs older than', 'motopress-hotel-booking' ), 'label' => __( 'Automatically delete sync logs older than', 'motopress-hotel-booking' ),
'list' => array( 'list' => array(

View File

@@ -69,7 +69,7 @@ class AttributesCPT extends EditableCPT {
$args = array( $args = array(
'labels' => $labels, 'labels' => $labels,
'public' => false, 'public' => false,
'show_ui' => false, 'show_ui' => true,
'show_in_menu' => MPHB()->postTypes()->roomType()->getMenuSlug(), 'show_in_menu' => MPHB()->postTypes()->roomType()->getMenuSlug(),
'supports' => array( 'title', 'page-attributes' ), 'supports' => array( 'title', 'page-attributes' ),
'register_meta_box_cb' => array( $this, 'registerMetaBoxes' ), 'register_meta_box_cb' => array( $this, 'registerMetaBoxes' ),

View File

@@ -114,7 +114,7 @@ class AdminScriptManager extends ScriptManager {
'dateFormat' => MPHB()->settings()->dateTime()->getDateFormatJS(), 'dateFormat' => MPHB()->settings()->dateTime()->getDateFormatJS(),
'dateTransferFormat' => MPHB()->settings()->dateTime()->getDateTransferFormatJS(), 'dateTransferFormat' => MPHB()->settings()->dateTime()->getDateTransferFormatJS(),
'datepickerClass' => MPHB()->settings()->main()->getDatepickerThemeClass(), 'datepickerClass' => MPHB()->settings()->main()->getDatepickerThemeClass(),
'upgradeToPremiumMsgHtml' => mphb_upgrade_to_premium_message(), 'upgradeToPremiumMsgHtml' => '',
'currency' => array( 'currency' => array(
'price_format' => MPHB()->settings()->currency()->getPriceFormat( $currencySymbol, $currencyPosition ), 'price_format' => MPHB()->settings()->currency()->getPriceFormat( $currencySymbol, $currencyPosition ),
'decimals' => MPHB()->settings()->currency()->getPriceDecimalsCount(), 'decimals' => MPHB()->settings()->currency()->getPriceDecimalsCount(),

View File

@@ -111,30 +111,10 @@ class LicenseSettings {
* @return array [ status, expires ] * @return array [ status, expires ]
*/ */
public function getLicenseStatus() { public function getLicenseStatus() {
$defaultStatus = [ return [
'status' => 'undefined', 'status' => 'valid',
'expires' => self::EXPIRATION_LIFETIME, '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 * @return bool
*/ */
public function isEnabled() { public function isEnabled() {
return false; return true;
} }
/** /**

View File

@@ -4910,7 +4910,7 @@ msgid "Payment (#%s) for this booking is on hold"
msgstr "Opłata (#%s) za tą rezerwację jest w oczekiwaniu" msgstr "Opłata (#%s) za tą rezerwację jest w oczekiwaniu"
msgid "Rate Info" msgid "Rate Info"
msgstr "Oceny" msgstr "Ceny"
msgid "Season" msgid "Season"
msgstr "Sezon" 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. #. translators: The value a hotel wishes to sell their rooms. Also called the Cost, Value, Tariff or Room charge.
msgid "Rates" msgid "Rates"
msgstr "Oceny" msgstr "Ceny"
msgctxt "Add New Rate" msgctxt "Add New Rate"
msgid "Add New" msgid "Add New"

View File

@@ -580,9 +580,8 @@ private $upgradeToPremiumMenuPage;
$this->attributesMenuPage = new \MPHB\Admin\MenuPages\AttributesMenuPage('mphb_room_attribute', $attributesSettings); $this->attributesMenuPage = new \MPHB\Admin\MenuPages\AttributesMenuPage('mphb_room_attribute', $attributesSettings);
$upgradeToPremiumSettings = array( 'order' => 200 ); // "Go Premium" menu page removed
// $this->upgradeToPremiumMenuPage = new \MPHB\Admin\MenuPages\UpgradeToPremiumMenuPage( 'mphb_premium', $upgradeToPremiumSettings );
$this->upgradeToPremiumMenuPage = new \MPHB\Admin\MenuPages\UpgradeToPremiumMenuPage( 'mphb_premium', $upgradeToPremiumSettings );
$reportsPageSettings = array( $reportsPageSettings = array(
'capability' => \MPHB\UsersAndRoles\CapabilitiesAndRoles::VIEW_REPORTS, '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\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 );
} }
} }