1603 lines
52 KiB
PHP
1603 lines
52 KiB
PHP
<?php
|
|
/**
|
|
* Admin Class
|
|
*
|
|
* @package YachtBooking
|
|
*/
|
|
|
|
namespace YachtBooking;
|
|
|
|
// Exit if accessed directly
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Admin class - handles admin panel functionality
|
|
*/
|
|
class Admin {
|
|
|
|
/**
|
|
* Single instance
|
|
*
|
|
* @var Admin
|
|
*/
|
|
private static $instance = null;
|
|
|
|
/**
|
|
* Get instance
|
|
*
|
|
* @return Admin
|
|
*/
|
|
public static function get_instance() {
|
|
if ( null === self::$instance ) {
|
|
self::$instance = new self();
|
|
}
|
|
return self::$instance;
|
|
}
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
private function __construct() {
|
|
add_action( 'admin_menu', array( $this, 'register_admin_menu' ), 9 );
|
|
add_action( 'admin_init', array( $this, 'process_bulk_actions' ) );
|
|
add_action( 'admin_init', array( $this, 'process_single_actions' ) );
|
|
add_action( 'admin_init', array( $this, 'process_yacht_save' ) );
|
|
add_action( 'admin_init', array( $this, 'process_booking_actions' ) );
|
|
add_action( 'admin_init', array( $this, 'process_settings_save' ) );
|
|
add_action( 'admin_init', array( $this, 'process_export_download' ) );
|
|
add_action( 'yacht_booking_status_changed', array( $this, 'send_customer_notification' ), 10, 2 );
|
|
add_action( 'admin_notices', array( $this, 'display_admin_notices' ) );
|
|
}
|
|
|
|
/**
|
|
* Process settings save (runs on admin_init BEFORE any output)
|
|
*/
|
|
public function process_settings_save() {
|
|
// Only process on settings page
|
|
if ( ! isset( $_GET['page'] ) || $_GET['page'] !== 'yacht-bookings-settings' ) {
|
|
return;
|
|
}
|
|
|
|
if ( ! current_user_can( 'yacht_booking_manage_settings' ) ) {
|
|
return;
|
|
}
|
|
|
|
// Handle general settings save
|
|
if ( isset( $_POST['yacht_booking_save_settings'] ) ) {
|
|
check_admin_referer( 'yacht_booking_save_settings' );
|
|
$this->save_settings();
|
|
}
|
|
|
|
// Handle email templates save.
|
|
if ( isset( $_POST['yacht_booking_save_email_templates'] ) ) {
|
|
check_admin_referer( 'yacht_booking_save_email_templates' );
|
|
$this->save_email_templates();
|
|
}
|
|
|
|
// Handle reset email templates.
|
|
if ( isset( $_POST['yacht_booking_reset_email_templates'] ) ) {
|
|
check_admin_referer( 'yacht_booking_save_email_templates' );
|
|
Email_Templates::reset_templates();
|
|
wp_safe_redirect( admin_url( 'admin.php?page=yacht-bookings-settings&tab=email-templates&templates_reset=1' ) );
|
|
exit;
|
|
}
|
|
|
|
// Handle global iCal settings save.
|
|
if ( isset( $_POST['yacht_booking_save_global_ical'] ) ) {
|
|
check_admin_referer( 'yacht_booking_save_global_ical' );
|
|
$import_url = isset( $_POST['global_ical_import_url'] ) ? esc_url_raw( wp_unslash( $_POST['global_ical_import_url'] ) ) : '';
|
|
update_option( 'yacht_booking_global_ical_import_url', $import_url );
|
|
|
|
$sync_mode = isset( $_POST['ical_sync_mode'] ) ? sanitize_text_field( wp_unslash( $_POST['ical_sync_mode'] ) ) : 'per_yacht';
|
|
if ( ! in_array( $sync_mode, array( 'per_yacht', 'global' ), true ) ) {
|
|
$sync_mode = 'per_yacht';
|
|
}
|
|
update_option( 'yacht_booking_ical_sync_mode', $sync_mode );
|
|
|
|
wp_safe_redirect( admin_url( 'admin.php?page=yacht-bookings-settings&tab=google-calendar&global_ical_saved=1' ) );
|
|
exit;
|
|
}
|
|
|
|
// Handle global iCal token regeneration.
|
|
if ( isset( $_POST['yacht_booking_regenerate_global_ical_token'] ) ) {
|
|
check_admin_referer( 'yacht_booking_regenerate_global_ical_token' );
|
|
\YachtBooking\Integrations\ICal\ICal_Feed::regenerate_global_token();
|
|
wp_safe_redirect( admin_url( 'admin.php?page=yacht-bookings-settings&tab=google-calendar&token_regenerated=1' ) );
|
|
exit;
|
|
}
|
|
|
|
// Handle global iCal manual import trigger.
|
|
if ( isset( $_POST['yacht_booking_run_global_ical_import'] ) ) {
|
|
check_admin_referer( 'yacht_booking_run_global_ical_import' );
|
|
$result = \YachtBooking\Integrations\ICal\ICal_Import::run_global_import();
|
|
$arg = $result ? 'global_import_done=1' : 'global_import_failed=1';
|
|
wp_safe_redirect( admin_url( 'admin.php?page=yacht-bookings-settings&tab=google-calendar&' . $arg ) );
|
|
exit;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Display admin notices
|
|
*/
|
|
public function display_admin_notices() {
|
|
// Only show on settings page
|
|
if ( ! isset( $_GET['page'] ) || $_GET['page'] !== 'yacht-bookings-settings' ) {
|
|
return;
|
|
}
|
|
|
|
// Success: Settings saved
|
|
if ( isset( $_GET['saved'] ) ) {
|
|
?>
|
|
<div class="notice notice-success is-dismissible">
|
|
<p><strong><?php esc_html_e( 'Ustawienia zostały zapisane pomyślnie!', 'yacht-booking' ); ?></strong></p>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
// Success: Email templates saved.
|
|
if ( isset( $_GET['templates_saved'] ) ) {
|
|
?>
|
|
<div class="notice notice-success is-dismissible">
|
|
<p><strong><?php esc_html_e( 'Szablony email zostały zapisane.', 'yacht-booking' ); ?></strong></p>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
// Success: Email templates reset.
|
|
if ( isset( $_GET['templates_reset'] ) ) {
|
|
?>
|
|
<div class="notice notice-success is-dismissible">
|
|
<p><strong><?php esc_html_e( 'Szablony email zostały zresetowane do domyślnych.', 'yacht-booking' ); ?></strong></p>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
// Error
|
|
if ( isset( $_GET['error'] ) ) {
|
|
?>
|
|
<div class="notice notice-error is-dismissible">
|
|
<p><strong><?php esc_html_e( 'Wystąpił błąd. Spróbuj ponownie.', 'yacht-booking' ); ?></strong></p>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
if ( isset( $_GET['global_ical_saved'] ) ) {
|
|
?>
|
|
<div class="notice notice-success is-dismissible">
|
|
<p><strong><?php esc_html_e( 'Globalne ustawienia iCal zostały zapisane.', 'yacht-booking' ); ?></strong></p>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
if ( isset( $_GET['token_regenerated'] ) ) {
|
|
?>
|
|
<div class="notice notice-success is-dismissible">
|
|
<p><strong><?php esc_html_e( 'Wygenerowano nowy token globalnego feed iCal. Poprzedni URL został unieważniony — zaktualizuj subskrypcję w Google Calendar.', 'yacht-booking' ); ?></strong></p>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
if ( isset( $_GET['global_import_done'] ) ) {
|
|
?>
|
|
<div class="notice notice-success is-dismissible">
|
|
<p><strong><?php esc_html_e( 'Globalny import iCal wykonany. Sprawdź listę rezerwacji.', 'yacht-booking' ); ?></strong></p>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
if ( isset( $_GET['global_import_failed'] ) ) {
|
|
?>
|
|
<div class="notice notice-error is-dismissible">
|
|
<p><strong><?php esc_html_e( 'Globalny import iCal nie powiódł się. Sprawdź czy URL jest poprawny i logi serwera.', 'yacht-booking' ); ?></strong></p>
|
|
</div>
|
|
<?php
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Register admin menu
|
|
*/
|
|
public function register_admin_menu() {
|
|
// Main menu page
|
|
add_menu_page(
|
|
__( 'Rezerwacje Jachtów', 'yacht-booking' ),
|
|
__( 'Rezerwacje Jachtów', 'yacht-booking' ),
|
|
'yacht_booking_manage_yachts',
|
|
'yacht-bookings',
|
|
array( $this, 'render_yachts_page' ),
|
|
'dashicons-palmtree',
|
|
30
|
|
);
|
|
|
|
// Submenu: Yachts (lista)
|
|
add_submenu_page(
|
|
'yacht-bookings',
|
|
__( 'Wszystkie Jachty', 'yacht-booking' ),
|
|
__( 'Wszystkie Jachty', 'yacht-booking' ),
|
|
'yacht_booking_manage_yachts',
|
|
'yacht-bookings',
|
|
array( $this, 'render_yachts_page' )
|
|
);
|
|
|
|
// Submenu: Add New Yacht
|
|
add_submenu_page(
|
|
'yacht-bookings',
|
|
__( 'Dodaj Jacht', 'yacht-booking' ),
|
|
__( 'Dodaj Jacht', 'yacht-booking' ),
|
|
'yacht_booking_manage_yachts',
|
|
'yacht-bookings-add-yacht',
|
|
array( $this, 'render_add_yacht_page' )
|
|
);
|
|
|
|
// Submenu: Bookings
|
|
add_submenu_page(
|
|
'yacht-bookings',
|
|
__( 'Wszystkie Rezerwacje', 'yacht-booking' ),
|
|
__( 'Rezerwacje', 'yacht-booking' ),
|
|
'yacht_booking_manage_bookings',
|
|
'yacht-bookings-list',
|
|
array( $this, 'render_bookings_page' )
|
|
);
|
|
|
|
// Submenu: Settings
|
|
add_submenu_page(
|
|
'yacht-bookings',
|
|
__( 'Ustawienia', 'yacht-booking' ),
|
|
__( 'Ustawienia', 'yacht-booking' ),
|
|
'yacht_booking_manage_settings',
|
|
'yacht-bookings-settings',
|
|
array( $this, 'render_settings_page' )
|
|
);
|
|
|
|
// Submenu: Inquiries
|
|
add_submenu_page(
|
|
'yacht-bookings',
|
|
__( 'Zapytania', 'yacht-booking' ),
|
|
__( 'Zapytania', 'yacht-booking' ),
|
|
'yacht_booking_manage_bookings',
|
|
'yacht-inquiries',
|
|
array( $this, 'render_inquiries_page' )
|
|
);
|
|
|
|
// Submenu: Export CSV.
|
|
add_submenu_page(
|
|
'yacht-bookings',
|
|
__( 'Eksport CSV', 'yacht-booking' ),
|
|
__( 'Eksport CSV', 'yacht-booking' ),
|
|
'yacht_booking_manage_bookings',
|
|
'yacht-bookings-export',
|
|
array( $this, 'render_export_page' )
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Process bulk actions
|
|
*/
|
|
public function process_bulk_actions() {
|
|
// Check if we're on the yacht list page
|
|
if ( ! isset( $_GET['page'] ) || $_GET['page'] !== 'yacht-bookings' ) {
|
|
return;
|
|
}
|
|
|
|
if ( ! current_user_can( 'yacht_booking_manage_yachts' ) ) {
|
|
return;
|
|
}
|
|
|
|
// Check for bulk delete
|
|
if ( isset( $_POST['action'] ) && $_POST['action'] === 'delete' && isset( $_POST['yacht'] ) ) {
|
|
check_admin_referer( 'bulk-yachts' );
|
|
|
|
$yacht_ids = array_map( 'intval', $_POST['yacht'] );
|
|
$deleted = 0;
|
|
|
|
foreach ( $yacht_ids as $yacht_id ) {
|
|
if ( $this->delete_yacht( $yacht_id ) ) {
|
|
$deleted++;
|
|
}
|
|
}
|
|
|
|
// Redirect with success message
|
|
$redirect_url = add_query_arg(
|
|
array(
|
|
'page' => 'yacht-bookings',
|
|
'deleted' => $deleted,
|
|
),
|
|
admin_url( 'admin.php' )
|
|
);
|
|
wp_safe_redirect( $redirect_url );
|
|
exit;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Process single actions
|
|
*/
|
|
public function process_single_actions() {
|
|
// Check for single yacht delete
|
|
if ( isset( $_GET['action'] ) && $_GET['action'] === 'delete' && isset( $_GET['yacht'] ) ) {
|
|
if ( ! current_user_can( 'yacht_booking_manage_yachts' ) ) {
|
|
return;
|
|
}
|
|
|
|
$yacht_id = (int) $_GET['yacht'];
|
|
|
|
check_admin_referer( 'delete_yacht_' . $yacht_id );
|
|
|
|
if ( $this->delete_yacht( $yacht_id ) ) {
|
|
$redirect_url = add_query_arg(
|
|
array(
|
|
'page' => 'yacht-bookings',
|
|
'deleted' => 1,
|
|
),
|
|
admin_url( 'admin.php' )
|
|
);
|
|
wp_safe_redirect( $redirect_url );
|
|
exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete yacht and cascade delete bookings
|
|
*
|
|
* @param int $yacht_id Yacht ID.
|
|
* @return bool
|
|
*/
|
|
private function delete_yacht( $yacht_id ) {
|
|
// Get all bookings for this yacht
|
|
$bookings = get_posts(
|
|
array(
|
|
'post_type' => 'yacht_booking',
|
|
'posts_per_page' => -1,
|
|
'meta_query' => array(
|
|
array(
|
|
'key' => '_booking_yacht_id',
|
|
'value' => $yacht_id,
|
|
),
|
|
),
|
|
'fields' => 'ids',
|
|
)
|
|
);
|
|
|
|
// Delete all bookings
|
|
foreach ( $bookings as $booking_id ) {
|
|
Availability::clear_booking_availability( $booking_id );
|
|
wp_delete_post( $booking_id, true );
|
|
}
|
|
|
|
// Delete yacht
|
|
wp_delete_post( $yacht_id, true );
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Save yacht
|
|
*
|
|
* @param array $data POST data.
|
|
* @param int $yacht_id Yacht ID (0 for new).
|
|
* @return int|false Yacht ID on success, false on failure.
|
|
*/
|
|
private function save_yacht( $data, $yacht_id = 0 ) {
|
|
// Validate
|
|
$title = isset( $data['yacht_title'] ) ? sanitize_text_field( wp_unslash( $data['yacht_title'] ) ) : '';
|
|
$content = isset( $data['yacht_description'] ) ? wp_kses_post( wp_unslash( $data['yacht_description'] ) ) : '';
|
|
|
|
if ( empty( $title ) ) {
|
|
return false;
|
|
}
|
|
|
|
// Prepare post data
|
|
$post_data = array(
|
|
'post_type' => 'yacht',
|
|
'post_title' => $title,
|
|
'post_content' => $content,
|
|
'post_status' => 'publish',
|
|
);
|
|
|
|
if ( $yacht_id ) {
|
|
$post_data['ID'] = $yacht_id;
|
|
$saved_id = wp_update_post( $post_data );
|
|
} else {
|
|
$saved_id = wp_insert_post( $post_data );
|
|
}
|
|
|
|
if ( is_wp_error( $saved_id ) ) {
|
|
return false;
|
|
}
|
|
|
|
// Save GCal alias for global iCal import matching.
|
|
$gcal_alias = isset( $data['yacht_gcal_alias'] ) ? sanitize_text_field( wp_unslash( $data['yacht_gcal_alias'] ) ) : '';
|
|
Yacht::update_gcal_alias( $saved_id, $gcal_alias );
|
|
|
|
// Save admin-selected color for aggregated calendar.
|
|
$yacht_color = isset( $data['yacht_color'] ) ? sanitize_text_field( wp_unslash( $data['yacht_color'] ) ) : '';
|
|
Yacht::update_color( $saved_id, $yacht_color );
|
|
|
|
return $saved_id;
|
|
}
|
|
|
|
/**
|
|
* Render yachts list page
|
|
*/
|
|
public function render_yachts_page() {
|
|
// Load Yacht List Table
|
|
require_once YACHT_BOOKING_PLUGIN_DIR . 'admin/class-yacht-list-table.php';
|
|
|
|
$list_table = new Yacht_List_Table();
|
|
$list_table->prepare_items();
|
|
|
|
?>
|
|
<div class="wrap">
|
|
<h1 class="wp-heading-inline"><?php esc_html_e( 'Jachty', 'yacht-booking' ); ?></h1>
|
|
<a href="<?php echo esc_url( admin_url( 'admin.php?page=yacht-bookings-add-yacht' ) ); ?>" class="page-title-action">
|
|
<?php esc_html_e( 'Dodaj nowy', 'yacht-booking' ); ?>
|
|
</a>
|
|
|
|
<?php
|
|
// Display success/error messages
|
|
if ( isset( $_GET['deleted'] ) ) {
|
|
$count = (int) $_GET['deleted'];
|
|
printf(
|
|
'<div class="notice notice-success is-dismissible"><p>%s</p></div>',
|
|
esc_html( sprintf( _n( 'Usunięto %d jacht.', 'Usunięto %d jachtów.', $count, 'yacht-booking' ), $count ) )
|
|
);
|
|
}
|
|
?>
|
|
|
|
<hr class="wp-header-end">
|
|
|
|
<form method="get">
|
|
<input type="hidden" name="page" value="yacht-bookings" />
|
|
<?php
|
|
$list_table->search_box( __( 'Szukaj jachtów', 'yacht-booking' ), 'yacht' );
|
|
?>
|
|
</form>
|
|
|
|
<form method="post">
|
|
<?php
|
|
$list_table->display();
|
|
?>
|
|
</form>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
/**
|
|
* Render add/edit yacht page
|
|
*/
|
|
public function render_add_yacht_page() {
|
|
$yacht_id = isset( $_GET['yacht_id'] ) ? (int) $_GET['yacht_id'] : 0;
|
|
$yacht = $yacht_id ? get_post( $yacht_id ) : null;
|
|
|
|
// Include edit form view
|
|
require_once YACHT_BOOKING_PLUGIN_DIR . 'admin/views/yacht-edit.php';
|
|
}
|
|
|
|
/**
|
|
* Process add/edit yacht save before any admin output.
|
|
*/
|
|
public function process_yacht_save() {
|
|
if ( ! isset( $_GET['page'] ) || 'yacht-bookings-add-yacht' !== $_GET['page'] ) {
|
|
return;
|
|
}
|
|
|
|
if ( ! isset( $_POST['yacht_booking_save_yacht'] ) ) {
|
|
return;
|
|
}
|
|
|
|
if ( ! current_user_can( 'yacht_booking_manage_yachts' ) ) {
|
|
return;
|
|
}
|
|
|
|
check_admin_referer( 'yacht_booking_save_yacht', 'yacht_booking_nonce' );
|
|
|
|
$yacht_id = isset( $_GET['yacht_id'] ) ? (int) $_GET['yacht_id'] : 0;
|
|
$saved_id = $this->save_yacht( $_POST, $yacht_id );
|
|
|
|
if ( ! $saved_id ) {
|
|
return;
|
|
}
|
|
|
|
$redirect_url = add_query_arg(
|
|
array(
|
|
'page' => 'yacht-bookings-add-yacht',
|
|
'yacht_id' => $saved_id,
|
|
'saved' => 1,
|
|
),
|
|
admin_url( 'admin.php' )
|
|
);
|
|
|
|
wp_safe_redirect( $redirect_url );
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Render bookings list page
|
|
*/
|
|
public function render_bookings_page() {
|
|
// Load Booking List Table
|
|
require_once YACHT_BOOKING_PLUGIN_DIR . 'admin/class-booking-list-table.php';
|
|
|
|
$list_table = new Booking_List_Table();
|
|
$list_table->prepare_items();
|
|
|
|
?>
|
|
<div class="wrap">
|
|
<h1 class="wp-heading-inline"><?php esc_html_e( 'Rezerwacje', 'yacht-booking' ); ?></h1>
|
|
<a href="<?php echo esc_url( admin_url( 'admin.php?page=yacht-bookings-export' ) ); ?>" class="page-title-action">
|
|
<?php esc_html_e( 'Eksport CSV', 'yacht-booking' ); ?>
|
|
</a>
|
|
|
|
<?php
|
|
// Display success/error messages
|
|
if ( isset( $_GET['approved'] ) ) {
|
|
$count = (int) $_GET['approved'];
|
|
printf(
|
|
'<div class="notice notice-success is-dismissible"><p>%s</p></div>',
|
|
esc_html( sprintf( _n( 'Zatwierdzono %d rezerwację.', 'Zatwierdzono %d rezerwacji.', $count, 'yacht-booking' ), $count ) )
|
|
);
|
|
}
|
|
|
|
if ( isset( $_GET['cancelled'] ) ) {
|
|
$count = (int) $_GET['cancelled'];
|
|
printf(
|
|
'<div class="notice notice-success is-dismissible"><p>%s</p></div>',
|
|
esc_html( sprintf( _n( 'Anulowano %d rezerwację.', 'Anulowano %d rezerwacji.', $count, 'yacht-booking' ), $count ) )
|
|
);
|
|
}
|
|
|
|
if ( isset( $_GET['deleted'] ) ) {
|
|
$count = (int) $_GET['deleted'];
|
|
printf(
|
|
'<div class="notice notice-success is-dismissible"><p>%s</p></div>',
|
|
esc_html( sprintf( _n( 'Usunięto %d rezerwację.', 'Usunięto %d rezerwacji.', $count, 'yacht-booking' ), $count ) )
|
|
);
|
|
}
|
|
?>
|
|
|
|
<hr class="wp-header-end">
|
|
|
|
<form method="get">
|
|
<input type="hidden" name="page" value="yacht-bookings-list" />
|
|
<?php
|
|
$list_table->search_box( __( 'Szukaj rezerwacji', 'yacht-booking' ), 'booking' );
|
|
$list_table->views();
|
|
?>
|
|
</form>
|
|
|
|
<form method="post">
|
|
<?php
|
|
$list_table->display();
|
|
?>
|
|
</form>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
/**
|
|
* Render CSV export page.
|
|
*/
|
|
public function render_export_page() {
|
|
if ( ! current_user_can( 'yacht_booking_manage_bookings' ) ) {
|
|
wp_die( esc_html__( 'Brak uprawnień.', 'yacht-booking' ) );
|
|
}
|
|
|
|
$filters = $this->get_export_filters();
|
|
$yachts = get_posts(
|
|
array(
|
|
'post_type' => 'yacht',
|
|
'posts_per_page' => -1,
|
|
'orderby' => 'title',
|
|
'order' => 'ASC',
|
|
)
|
|
);
|
|
?>
|
|
<div class="wrap">
|
|
<h1><?php esc_html_e( 'Eksport Rezerwacji (CSV)', 'yacht-booking' ); ?></h1>
|
|
<p><?php esc_html_e( 'Wygeneruj plik CSV z rezerwacjami i wybranymi filtrami.', 'yacht-booking' ); ?></p>
|
|
|
|
<form method="get" action="">
|
|
<input type="hidden" name="page" value="yacht-bookings-export">
|
|
<?php wp_nonce_field( 'yacht_booking_export_csv', 'yacht_booking_export_nonce' ); ?>
|
|
|
|
<table class="form-table">
|
|
<tr>
|
|
<th scope="row">
|
|
<label for="status_filter"><?php esc_html_e( 'Status', 'yacht-booking' ); ?></label>
|
|
</th>
|
|
<td>
|
|
<select id="status_filter" name="status_filter">
|
|
<option value="all" <?php selected( $filters['status_filter'], 'all' ); ?>>
|
|
<?php esc_html_e( 'Wszystkie', 'yacht-booking' ); ?>
|
|
</option>
|
|
<option value="pending" <?php selected( $filters['status_filter'], 'pending' ); ?>>
|
|
<?php esc_html_e( 'Oczekujące', 'yacht-booking' ); ?>
|
|
</option>
|
|
<option value="confirmed" <?php selected( $filters['status_filter'], 'confirmed' ); ?>>
|
|
<?php esc_html_e( 'Potwierdzone', 'yacht-booking' ); ?>
|
|
</option>
|
|
<option value="cancelled" <?php selected( $filters['status_filter'], 'cancelled' ); ?>>
|
|
<?php esc_html_e( 'Anulowane', 'yacht-booking' ); ?>
|
|
</option>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row">
|
|
<label for="yacht_filter"><?php esc_html_e( 'Jacht', 'yacht-booking' ); ?></label>
|
|
</th>
|
|
<td>
|
|
<select id="yacht_filter" name="yacht_filter">
|
|
<option value="0"><?php esc_html_e( 'Wszystkie jachty', 'yacht-booking' ); ?></option>
|
|
<?php foreach ( $yachts as $yacht ) : ?>
|
|
<option value="<?php echo esc_attr( $yacht->ID ); ?>" <?php selected( (int) $filters['yacht_filter'], (int) $yacht->ID ); ?>>
|
|
<?php echo esc_html( $yacht->post_title ); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row">
|
|
<label for="date_from"><?php esc_html_e( 'Data od', 'yacht-booking' ); ?></label>
|
|
</th>
|
|
<td>
|
|
<input type="date" id="date_from" name="date_from" value="<?php echo esc_attr( $filters['date_from'] ); ?>">
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row">
|
|
<label for="date_to"><?php esc_html_e( 'Data do', 'yacht-booking' ); ?></label>
|
|
</th>
|
|
<td>
|
|
<input type="date" id="date_to" name="date_to" value="<?php echo esc_attr( $filters['date_to'] ); ?>">
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p class="submit">
|
|
<button type="submit" name="yacht_booking_export_csv" value="1" class="button button-primary">
|
|
<?php esc_html_e( 'Pobierz CSV', 'yacht-booking' ); ?>
|
|
</button>
|
|
</p>
|
|
</form>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
/**
|
|
* Handle CSV export download.
|
|
*/
|
|
public function process_export_download() {
|
|
if ( ! isset( $_GET['page'] ) || 'yacht-bookings-export' !== $_GET['page'] ) {
|
|
return;
|
|
}
|
|
|
|
if ( ! isset( $_GET['yacht_booking_export_csv'] ) ) {
|
|
return;
|
|
}
|
|
|
|
if ( ! current_user_can( 'yacht_booking_manage_bookings' ) ) {
|
|
return;
|
|
}
|
|
|
|
$nonce = isset( $_GET['yacht_booking_export_nonce'] ) ? sanitize_text_field( wp_unslash( $_GET['yacht_booking_export_nonce'] ) ) : '';
|
|
if ( ! wp_verify_nonce( $nonce, 'yacht_booking_export_csv' ) ) {
|
|
wp_die( esc_html__( 'Nieprawidłowy token bezpieczeństwa.', 'yacht-booking' ) );
|
|
}
|
|
|
|
$filters = $this->get_export_filters();
|
|
$args = $this->get_export_query_args( $filters );
|
|
$bookings = get_posts( $args );
|
|
|
|
nocache_headers();
|
|
|
|
$filename = 'yacht-bookings-' . gmdate( 'Ymd-His' ) . '.csv';
|
|
header( 'Content-Type: text/csv; charset=UTF-8' );
|
|
header( 'Content-Disposition: attachment; filename=' . $filename );
|
|
|
|
$output = fopen( 'php://output', 'w' );
|
|
if ( false === $output ) {
|
|
exit;
|
|
}
|
|
|
|
// UTF-8 BOM for Excel compatibility.
|
|
fwrite( $output, chr( 0xEF ) . chr( 0xBB ) . chr( 0xBF ) );
|
|
|
|
fputcsv(
|
|
$output,
|
|
array(
|
|
'booking_id',
|
|
'yacht',
|
|
'customer_name',
|
|
'customer_email',
|
|
'customer_phone',
|
|
'start_date',
|
|
'end_date',
|
|
'status',
|
|
'total_price',
|
|
'created_at',
|
|
),
|
|
';'
|
|
);
|
|
|
|
$status_labels = array(
|
|
'pending' => __( 'Oczekująca', 'yacht-booking' ),
|
|
'confirmed' => __( 'Potwierdzona', 'yacht-booking' ),
|
|
'cancelled' => __( 'Anulowana', 'yacht-booking' ),
|
|
);
|
|
|
|
foreach ( $bookings as $booking ) {
|
|
$booking_id = $booking->ID;
|
|
$yacht_id = Booking::get_yacht_id( $booking_id );
|
|
$yacht = get_post( $yacht_id );
|
|
$status = Booking::get_status( $booking_id );
|
|
|
|
fputcsv(
|
|
$output,
|
|
array(
|
|
$booking_id,
|
|
$yacht ? $yacht->post_title : '',
|
|
Booking::get_customer_name( $booking_id ),
|
|
Booking::get_customer_email( $booking_id ),
|
|
Booking::get_customer_phone( $booking_id ),
|
|
Settings::format_date( Booking::get_start_date( $booking_id ) ),
|
|
Settings::format_date( Booking::get_end_date( $booking_id ) ),
|
|
isset( $status_labels[ $status ] ) ? $status_labels[ $status ] : $status,
|
|
Settings::format_price( Booking::get_total_price( $booking_id ) ),
|
|
get_the_date( Settings::get_date_format() . ' H:i', $booking ),
|
|
),
|
|
';'
|
|
);
|
|
}
|
|
|
|
fclose( $output );
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Get sanitized export filters from query string.
|
|
*
|
|
* @return array
|
|
*/
|
|
private function get_export_filters() {
|
|
$status_filter = isset( $_GET['status_filter'] ) ? sanitize_text_field( wp_unslash( $_GET['status_filter'] ) ) : 'all';
|
|
$yacht_filter = isset( $_GET['yacht_filter'] ) ? absint( $_GET['yacht_filter'] ) : 0;
|
|
$date_from = isset( $_GET['date_from'] ) ? sanitize_text_field( wp_unslash( $_GET['date_from'] ) ) : '';
|
|
$date_to = isset( $_GET['date_to'] ) ? sanitize_text_field( wp_unslash( $_GET['date_to'] ) ) : '';
|
|
|
|
if ( ! in_array( $status_filter, array( 'all', 'pending', 'confirmed', 'cancelled' ), true ) ) {
|
|
$status_filter = 'all';
|
|
}
|
|
|
|
if ( ! preg_match( '/^\d{4}-\d{2}-\d{2}$/', $date_from ) ) {
|
|
$date_from = '';
|
|
}
|
|
|
|
if ( ! preg_match( '/^\d{4}-\d{2}-\d{2}$/', $date_to ) ) {
|
|
$date_to = '';
|
|
}
|
|
|
|
return array(
|
|
'status_filter' => $status_filter,
|
|
'yacht_filter' => $yacht_filter,
|
|
'date_from' => $date_from,
|
|
'date_to' => $date_to,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Build WP_Query args for export.
|
|
*
|
|
* @param array $filters Export filters.
|
|
* @return array
|
|
*/
|
|
private function get_export_query_args( $filters ) {
|
|
$args = array(
|
|
'post_type' => 'yacht_booking',
|
|
'post_status' => 'publish',
|
|
'posts_per_page' => -1,
|
|
'orderby' => 'date',
|
|
'order' => 'DESC',
|
|
);
|
|
|
|
$meta_query = array();
|
|
|
|
if ( 'all' !== $filters['status_filter'] ) {
|
|
$meta_query[] = array(
|
|
'key' => '_booking_status',
|
|
'value' => $filters['status_filter'],
|
|
);
|
|
}
|
|
|
|
if ( ! empty( $filters['yacht_filter'] ) ) {
|
|
$meta_query[] = array(
|
|
'key' => '_booking_yacht_id',
|
|
'value' => $filters['yacht_filter'],
|
|
);
|
|
}
|
|
|
|
if ( ! empty( $filters['date_from'] ) ) {
|
|
$meta_query[] = array(
|
|
'key' => '_booking_end_date',
|
|
'value' => $filters['date_from'],
|
|
'compare' => '>=',
|
|
'type' => 'DATE',
|
|
);
|
|
}
|
|
|
|
if ( ! empty( $filters['date_to'] ) ) {
|
|
$meta_query[] = array(
|
|
'key' => '_booking_start_date',
|
|
'value' => $filters['date_to'],
|
|
'compare' => '<=',
|
|
'type' => 'DATE',
|
|
);
|
|
}
|
|
|
|
if ( ! empty( $meta_query ) ) {
|
|
$args['meta_query'] = array_merge( array( 'relation' => 'AND' ), $meta_query );
|
|
}
|
|
|
|
return $args;
|
|
}
|
|
|
|
/**
|
|
* Render settings page
|
|
*/
|
|
/**
|
|
* Render inquiries admin page
|
|
*/
|
|
public function render_inquiries_page() {
|
|
if ( ! current_user_can( 'yacht_booking_manage_bookings' ) ) {
|
|
wp_die( esc_html__( 'Brak uprawnień.', 'yacht-booking' ) );
|
|
}
|
|
|
|
// Handle view email action
|
|
if ( isset( $_GET['action'] ) && 'view_email' === $_GET['action'] && isset( $_GET['inquiry'] ) ) {
|
|
$inquiry_id = absint( $_GET['inquiry'] );
|
|
check_admin_referer( 'view_email_' . $inquiry_id );
|
|
|
|
$type = isset( $_GET['type'] ) && 'customer' === $_GET['type'] ? 'customer' : 'admin';
|
|
$body = 'admin' === $type
|
|
? Inquiry::get_admin_email_body( $inquiry_id )
|
|
: Inquiry::get_customer_email_body( $inquiry_id );
|
|
|
|
$label = 'admin' === $type
|
|
? __( 'Email wysłany do administratora', 'yacht-booking' )
|
|
: __( 'Email wysłany do klienta', 'yacht-booking' );
|
|
|
|
echo '<div class="wrap">';
|
|
echo '<h1>' . esc_html( $label ) . ' — #' . esc_html( $inquiry_id ) . '</h1>';
|
|
echo '<p><a href="' . esc_url( admin_url( 'admin.php?page=yacht-inquiries' ) ) . '">← '
|
|
. esc_html__( 'Wróć do listy zapytań', 'yacht-booking' ) . '</a></p>';
|
|
echo '<div style="background: #fff; padding: 20px; border: 1px solid #ccd0d4; border-radius: 4px; max-width: 700px;">';
|
|
echo $body ? wp_kses_post( $body ) : '<p><em>' . esc_html__( 'Brak treści emaila.', 'yacht-booking' ) . '</em></p>';
|
|
echo '</div></div>';
|
|
return;
|
|
}
|
|
|
|
// Handle delete action
|
|
if ( isset( $_GET['action'] ) && 'delete' === $_GET['action'] && isset( $_GET['inquiry'] ) ) {
|
|
$inquiry_id = absint( $_GET['inquiry'] );
|
|
check_admin_referer( 'delete_inquiry_' . $inquiry_id );
|
|
wp_delete_post( $inquiry_id, true );
|
|
wp_safe_redirect( admin_url( 'admin.php?page=yacht-inquiries&deleted=1' ) );
|
|
exit;
|
|
}
|
|
|
|
// Handle bulk delete
|
|
if ( isset( $_POST['action'] ) && 'delete' === $_POST['action'] && ! empty( $_POST['inquiry'] ) ) {
|
|
check_admin_referer( 'bulk-inquiries' );
|
|
$ids = array_map( 'absint', (array) $_POST['inquiry'] );
|
|
foreach ( $ids as $id ) {
|
|
wp_delete_post( $id, true );
|
|
}
|
|
wp_safe_redirect( admin_url( 'admin.php?page=yacht-inquiries&deleted=' . count( $ids ) ) );
|
|
exit;
|
|
}
|
|
|
|
require_once YACHT_BOOKING_PLUGIN_DIR . 'admin/class-inquiry-list-table.php';
|
|
|
|
$table = new Inquiry_List_Table();
|
|
$table->prepare_items();
|
|
|
|
?>
|
|
<div class="wrap">
|
|
<h1 class="wp-heading-inline"><?php esc_html_e( 'Zapytania o rezerwację', 'yacht-booking' ); ?></h1>
|
|
|
|
<?php if ( isset( $_GET['deleted'] ) ) : ?>
|
|
<div class="notice notice-success is-dismissible">
|
|
<p><?php esc_html_e( 'Zapytanie zostało usunięte.', 'yacht-booking' ); ?></p>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<form method="get">
|
|
<input type="hidden" name="page" value="yacht-inquiries">
|
|
<?php
|
|
$table->search_box( __( 'Szukaj', 'yacht-booking' ), 'inquiry-search' );
|
|
$table->display();
|
|
?>
|
|
</form>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
public function render_settings_page() {
|
|
// Load Google Calendar classes
|
|
if ( file_exists( YACHT_BOOKING_PLUGIN_DIR . 'integrations/google-calendar/class-oauth-handler.php' ) ) {
|
|
require_once YACHT_BOOKING_PLUGIN_DIR . 'integrations/google-calendar/class-oauth-handler.php';
|
|
}
|
|
if ( file_exists( YACHT_BOOKING_PLUGIN_DIR . 'integrations/google-calendar/class-gcal-service.php' ) ) {
|
|
require_once YACHT_BOOKING_PLUGIN_DIR . 'integrations/google-calendar/class-gcal-service.php';
|
|
}
|
|
|
|
// Get current tab
|
|
$active_tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : 'general';
|
|
|
|
?>
|
|
<div class="wrap">
|
|
<h1><?php esc_html_e( 'Ustawienia Rezerwacji Jachtów', 'yacht-booking' ); ?></h1>
|
|
|
|
<h2 class="nav-tab-wrapper">
|
|
<a href="?page=yacht-bookings-settings&tab=general" class="nav-tab <?php echo $active_tab === 'general' ? 'nav-tab-active' : ''; ?>">
|
|
<?php esc_html_e( 'Ustawienia ogólne', 'yacht-booking' ); ?>
|
|
</a>
|
|
<a href="?page=yacht-bookings-settings&tab=email-templates" class="nav-tab <?php echo $active_tab === 'email-templates' ? 'nav-tab-active' : ''; ?>">
|
|
<?php esc_html_e( 'Szablony Email', 'yacht-booking' ); ?>
|
|
</a>
|
|
<a href="?page=yacht-bookings-settings&tab=google-calendar" class="nav-tab <?php echo $active_tab === 'google-calendar' ? 'nav-tab-active' : ''; ?>">
|
|
<?php esc_html_e( 'Google Calendar', 'yacht-booking' ); ?>
|
|
</a>
|
|
</h2>
|
|
|
|
<div class="tab-content">
|
|
<?php
|
|
if ( $active_tab === 'general' ) {
|
|
$this->render_general_settings();
|
|
} elseif ( $active_tab === 'email-templates' ) {
|
|
$this->render_email_templates_settings();
|
|
} elseif ( $active_tab === 'google-calendar' ) {
|
|
$this->render_google_calendar_settings();
|
|
}
|
|
?>
|
|
</div>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
/**
|
|
* Render general settings tab
|
|
*/
|
|
private function render_general_settings() {
|
|
$booking_enabled = Settings::is_booking_enabled();
|
|
$default_status = Settings::get_default_status();
|
|
$email_from_name = Settings::get_email_from_name();
|
|
$email_from = Settings::get_email_from_address();
|
|
$date_format = Settings::get_date_format();
|
|
$currency_symbol = Settings::get_currency_symbol();
|
|
$terms_page_id = Settings::get_terms_page_id();
|
|
?>
|
|
<form method="post" action="">
|
|
<?php wp_nonce_field( 'yacht_booking_save_settings' ); ?>
|
|
|
|
<h2><?php esc_html_e( 'Ustawienia rezerwacji', 'yacht-booking' ); ?></h2>
|
|
<table class="form-table">
|
|
<tr>
|
|
<th scope="row">
|
|
<label for="booking_enabled"><?php esc_html_e( 'Rezerwacje online', 'yacht-booking' ); ?></label>
|
|
</th>
|
|
<td>
|
|
<label>
|
|
<input type="checkbox" name="booking_enabled" id="booking_enabled" value="1" <?php checked( $booking_enabled ); ?>>
|
|
<?php esc_html_e( 'Włącz rezerwacje online', 'yacht-booking' ); ?>
|
|
</label>
|
|
<p class="description">
|
|
<?php esc_html_e( 'Gdy wyłączone, klienci widzą tylko kalendarz dostępności bez możliwości rezerwacji.', 'yacht-booking' ); ?>
|
|
</p>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row">
|
|
<label for="default_status"><?php esc_html_e( 'Domyślny status rezerwacji', 'yacht-booking' ); ?></label>
|
|
</th>
|
|
<td>
|
|
<select name="default_status" id="default_status">
|
|
<option value="pending" <?php selected( $default_status, 'pending' ); ?>>
|
|
<?php esc_html_e( 'Oczekująca (wymaga zatwierdzenia)', 'yacht-booking' ); ?>
|
|
</option>
|
|
<option value="confirmed" <?php selected( $default_status, 'confirmed' ); ?>>
|
|
<?php esc_html_e( 'Potwierdzona (automatyczne zatwierdzenie)', 'yacht-booking' ); ?>
|
|
</option>
|
|
</select>
|
|
<p class="description">
|
|
<?php esc_html_e( 'Status przypisywany nowym rezerwacjom.', 'yacht-booking' ); ?>
|
|
</p>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h2><?php esc_html_e( 'Ustawienia email', 'yacht-booking' ); ?></h2>
|
|
<table class="form-table">
|
|
<tr>
|
|
<th scope="row">
|
|
<label for="email_from_name"><?php esc_html_e( 'Nazwa nadawcy', 'yacht-booking' ); ?></label>
|
|
</th>
|
|
<td>
|
|
<input type="text" name="email_from_name" id="email_from_name" value="<?php echo esc_attr( $email_from_name ); ?>" class="regular-text">
|
|
<p class="description">
|
|
<?php esc_html_e( 'Nazwa wyświetlana w emailach wysyłanych do klientów.', 'yacht-booking' ); ?>
|
|
</p>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row">
|
|
<label for="email_from"><?php esc_html_e( 'Adres email nadawcy', 'yacht-booking' ); ?></label>
|
|
</th>
|
|
<td>
|
|
<input type="email" name="email_from" id="email_from" value="<?php echo esc_attr( $email_from ); ?>" class="regular-text">
|
|
<p class="description">
|
|
<?php esc_html_e( 'Adres email używany jako nadawca w powiadomieniach.', 'yacht-booking' ); ?>
|
|
</p>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h2><?php esc_html_e( 'Ustawienia formatowania', 'yacht-booking' ); ?></h2>
|
|
<table class="form-table">
|
|
<tr>
|
|
<th scope="row">
|
|
<label for="date_format"><?php esc_html_e( 'Format daty', 'yacht-booking' ); ?></label>
|
|
</th>
|
|
<td>
|
|
<select name="date_format" id="date_format">
|
|
<option value="Y-m-d" <?php selected( $date_format, 'Y-m-d' ); ?>>YYYY-MM-DD (<?php echo esc_html( gmdate( 'Y-m-d' ) ); ?>)</option>
|
|
<option value="d/m/Y" <?php selected( $date_format, 'd/m/Y' ); ?>>DD/MM/YYYY (<?php echo esc_html( gmdate( 'd/m/Y' ) ); ?>)</option>
|
|
<option value="m/d/Y" <?php selected( $date_format, 'm/d/Y' ); ?>>MM/DD/YYYY (<?php echo esc_html( gmdate( 'm/d/Y' ) ); ?>)</option>
|
|
<option value="d.m.Y" <?php selected( $date_format, 'd.m.Y' ); ?>>DD.MM.YYYY (<?php echo esc_html( gmdate( 'd.m.Y' ) ); ?>)</option>
|
|
</select>
|
|
<p class="description">
|
|
<?php esc_html_e( 'Format wyświetlania dat w emailach i interfejsie.', 'yacht-booking' ); ?>
|
|
</p>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row">
|
|
<label for="currency_symbol"><?php esc_html_e( 'Symbol waluty', 'yacht-booking' ); ?></label>
|
|
</th>
|
|
<td>
|
|
<input type="text" name="currency_symbol" id="currency_symbol" value="<?php echo esc_attr( $currency_symbol ); ?>" class="small-text">
|
|
<p class="description">
|
|
<?php esc_html_e( 'Symbol waluty wyświetlany przy cenach (np. zł, €, $).', 'yacht-booking' ); ?>
|
|
</p>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h2><?php esc_html_e( 'Regulamin', 'yacht-booking' ); ?></h2>
|
|
<table class="form-table">
|
|
<tr>
|
|
<th scope="row">
|
|
<label for="terms_page_id"><?php esc_html_e( 'Strona regulaminu', 'yacht-booking' ); ?></label>
|
|
</th>
|
|
<td>
|
|
<?php
|
|
wp_dropdown_pages(
|
|
array(
|
|
'name' => 'terms_page_id',
|
|
'id' => 'terms_page_id',
|
|
'selected' => $terms_page_id,
|
|
'show_option_none' => __( '— Wybierz stronę —', 'yacht-booking' ),
|
|
'option_none_value' => 0,
|
|
)
|
|
);
|
|
?>
|
|
<p class="description">
|
|
<?php esc_html_e( 'Strona z regulaminem wyświetlana w formularzu rezerwacji.', 'yacht-booking' ); ?>
|
|
</p>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p class="submit">
|
|
<input type="submit" name="yacht_booking_save_settings" class="button-primary" value="<?php esc_attr_e( 'Zapisz ustawienia', 'yacht-booking' ); ?>">
|
|
</p>
|
|
</form>
|
|
<?php
|
|
}
|
|
|
|
/**
|
|
* Render email template settings tab.
|
|
*/
|
|
private function render_email_templates_settings() {
|
|
$templates = Email_Templates::get_templates();
|
|
$labels = Email_Templates::get_template_labels();
|
|
$available = Email_Templates::get_available_tags();
|
|
$preview_data = array(
|
|
'booking_id' => 1234,
|
|
'yacht_name' => __( 'Oceanic 42', 'yacht-booking' ),
|
|
'customer_name' => __( 'Jan Kowalski', 'yacht-booking' ),
|
|
'customer_email' => 'jan.kowalski@example.com',
|
|
'customer_phone' => '+48 500 600 700',
|
|
'start_date' => Settings::format_date( gmdate( 'Y-m-d', strtotime( '+7 days' ) ) ),
|
|
'end_date' => Settings::format_date( gmdate( 'Y-m-d', strtotime( '+10 days' ) ) ),
|
|
'days' => 4,
|
|
'total_price' => Settings::format_price( 2499.00 ),
|
|
'status' => __( 'Potwierdzona', 'yacht-booking' ),
|
|
'admin_link' => admin_url( 'admin.php?page=yacht-bookings-list' ),
|
|
);
|
|
?>
|
|
<form method="post" action="">
|
|
<?php wp_nonce_field( 'yacht_booking_save_email_templates' ); ?>
|
|
|
|
<h2><?php esc_html_e( 'Szablony Email', 'yacht-booking' ); ?></h2>
|
|
<p><?php esc_html_e( 'Skonfiguruj tematy i treści wiadomości email. Możesz używać poniższych tagów.', 'yacht-booking' ); ?></p>
|
|
|
|
<p>
|
|
<?php foreach ( $available as $tag => $label ) : ?>
|
|
<code><?php echo esc_html( $tag ); ?></code> - <?php echo esc_html( $label ); ?><br>
|
|
<?php endforeach; ?>
|
|
</p>
|
|
|
|
<?php foreach ( $labels as $type => $label ) : ?>
|
|
<?php
|
|
$template = isset( $templates[ $type ] ) ? $templates[ $type ] : array( 'subject' => '', 'body' => '' );
|
|
$preview = Email_Templates::compile( $type, $preview_data );
|
|
?>
|
|
<hr>
|
|
<h3><?php echo esc_html( $label ); ?></h3>
|
|
<table class="form-table">
|
|
<tr>
|
|
<th scope="row">
|
|
<label for="template_subject_<?php echo esc_attr( $type ); ?>">
|
|
<?php esc_html_e( 'Temat', 'yacht-booking' ); ?>
|
|
</label>
|
|
</th>
|
|
<td>
|
|
<input
|
|
type="text"
|
|
class="regular-text"
|
|
id="template_subject_<?php echo esc_attr( $type ); ?>"
|
|
name="template_subject[<?php echo esc_attr( $type ); ?>]"
|
|
value="<?php echo esc_attr( $template['subject'] ); ?>"
|
|
/>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row">
|
|
<?php esc_html_e( 'Treść', 'yacht-booking' ); ?>
|
|
</th>
|
|
<td>
|
|
<?php
|
|
wp_editor(
|
|
$template['body'],
|
|
'yacht_booking_template_body_' . $type,
|
|
array(
|
|
'textarea_name' => 'template_body[' . $type . ']',
|
|
'textarea_rows' => 8,
|
|
'media_buttons' => false,
|
|
'teeny' => true,
|
|
)
|
|
);
|
|
?>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row">
|
|
<?php esc_html_e( 'Podgląd', 'yacht-booking' ); ?>
|
|
</th>
|
|
<td>
|
|
<p><strong><?php esc_html_e( 'Temat:', 'yacht-booking' ); ?></strong> <?php echo esc_html( $preview['subject'] ); ?></p>
|
|
<div style="background: #fff; border: 1px solid #ccd0d4; padding: 12px;">
|
|
<?php echo wp_kses_post( $preview['body'] ); ?>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<?php endforeach; ?>
|
|
|
|
<p class="submit">
|
|
<button type="submit" name="yacht_booking_save_email_templates" class="button button-primary">
|
|
<?php esc_html_e( 'Zapisz szablony', 'yacht-booking' ); ?>
|
|
</button>
|
|
<button
|
|
type="submit"
|
|
name="yacht_booking_reset_email_templates"
|
|
class="button button-secondary"
|
|
onclick="return confirm('<?php echo esc_js( __( 'Przywrócić domyślne szablony email?', 'yacht-booking' ) ); ?>');"
|
|
>
|
|
<?php esc_html_e( 'Przywróć domyślne', 'yacht-booking' ); ?>
|
|
</button>
|
|
</p>
|
|
</form>
|
|
<?php
|
|
}
|
|
|
|
/**
|
|
* Save email templates.
|
|
*/
|
|
private function save_email_templates() {
|
|
$subjects = isset( $_POST['template_subject'] ) && is_array( $_POST['template_subject'] ) ? $_POST['template_subject'] : array();
|
|
$bodies = isset( $_POST['template_body'] ) && is_array( $_POST['template_body'] ) ? $_POST['template_body'] : array();
|
|
$templates = array();
|
|
|
|
foreach ( Email_Templates::get_default_templates() as $type => $default_template ) {
|
|
$templates[ $type ] = array(
|
|
'subject' => isset( $subjects[ $type ] ) ? $subjects[ $type ] : '',
|
|
'body' => isset( $bodies[ $type ] ) ? $bodies[ $type ] : '',
|
|
);
|
|
}
|
|
|
|
Email_Templates::save_templates( $templates );
|
|
|
|
wp_safe_redirect( admin_url( 'admin.php?page=yacht-bookings-settings&tab=email-templates&templates_saved=1' ) );
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Render Google Calendar settings tab
|
|
*/
|
|
private function render_google_calendar_settings() {
|
|
?>
|
|
<h2><?php esc_html_e( 'Synchronizacja z Google Calendar (iCal)', 'yacht-booking' ); ?></h2>
|
|
|
|
<?php
|
|
// =====================================================================
|
|
// Globalna synchronizacja iCal (jeden wspólny kalendarz Google,
|
|
// podział na jachty po prefiksie nazwy w tytule eventu).
|
|
// Działa niezależnie od OAuth — wystarczy publiczny URL kalendarza Google.
|
|
// =====================================================================
|
|
$global_import_url = (string) get_option( 'yacht_booking_global_ical_import_url', '' );
|
|
$global_export_url = \YachtBooking\Integrations\ICal\ICal_Feed::get_global_feed_url();
|
|
$last_global_run = (string) get_option( 'yacht_booking_global_ical_last_import', '' );
|
|
$ical_sync_mode = Settings::get_ical_sync_mode();
|
|
?>
|
|
<div class="card" style="margin-top: 30px;">
|
|
<h3><?php esc_html_e( 'Globalna synchronizacja iCal (jeden wspólny kalendarz)', 'yacht-booking' ); ?></h3>
|
|
<p class="description">
|
|
<?php esc_html_e( 'Mechanizm dwukierunkowej synchronizacji wszystkich jachtów z jednym kalendarzem Google, bez OAuth. Plugin rozpoznaje jacht po prefiksie tytułu eventu w formacie: "Nazwa jachtu - opis" (np. "Maja - Kowalski 5 osób"). Eventy bez rozpoznanego prefiksu są ignorowane.', 'yacht-booking' ); ?>
|
|
</p>
|
|
|
|
<h4><?php esc_html_e( 'Krok 1: Dodaj feed pluginu jako kalendarz w Google', 'yacht-booking' ); ?></h4>
|
|
<p class="description">
|
|
<?php esc_html_e( 'Skopiuj poniższy URL i dodaj go w Google Calendar: "Inne kalendarze" → "+ Dodaj" → "Z URL-a". Rezerwacje ze strony pojawią się w Twoim Google Calendar (Google odświeża subskrypcję co kilka godzin).', 'yacht-booking' ); ?>
|
|
</p>
|
|
<p>
|
|
<input
|
|
type="text"
|
|
readonly
|
|
value="<?php echo esc_attr( $global_export_url ); ?>"
|
|
class="regular-text code"
|
|
id="yacht-global-ical-export-url"
|
|
style="width: 100%; max-width: 600px;"
|
|
onclick="this.select();"
|
|
/>
|
|
<button type="button" class="button" onclick="navigator.clipboard.writeText(document.getElementById('yacht-global-ical-export-url').value); this.textContent='<?php echo esc_js( __( 'Skopiowano!', 'yacht-booking' ) ); ?>';">
|
|
<?php esc_html_e( 'Kopiuj', 'yacht-booking' ); ?>
|
|
</button>
|
|
</p>
|
|
<form method="post" action="" style="margin-top: 10px;" onsubmit="return confirm('<?php echo esc_js( __( 'Wygenerować nowy token? Poprzedni URL przestanie działać.', 'yacht-booking' ) ); ?>')">
|
|
<?php wp_nonce_field( 'yacht_booking_regenerate_global_ical_token' ); ?>
|
|
<button type="submit" name="yacht_booking_regenerate_global_ical_token" class="button button-secondary">
|
|
<?php esc_html_e( 'Wygeneruj nowy token', 'yacht-booking' ); ?>
|
|
</button>
|
|
<span class="description" style="margin-left: 10px;">
|
|
<?php esc_html_e( 'Unieważnia bieżący URL — używaj gdy podejrzewasz wyciek.', 'yacht-booking' ); ?>
|
|
</span>
|
|
</form>
|
|
|
|
<h4 style="margin-top: 25px;"><?php esc_html_e( 'Krok 2: Wklej iCal URL Twojego kalendarza Google', 'yacht-booking' ); ?></h4>
|
|
<p class="description">
|
|
<?php esc_html_e( 'W Google Calendar otwórz ustawienia kalendarza → "Tajny adres w formacie iCal" → skopiuj URL i wklej poniżej. Plugin pobiera ten kalendarz co godzinę i importuje rozpoznane eventy jako blokady.', 'yacht-booking' ); ?>
|
|
</p>
|
|
<form method="post" action="">
|
|
<?php wp_nonce_field( 'yacht_booking_save_global_ical' ); ?>
|
|
<table class="form-table">
|
|
<tr>
|
|
<th scope="row">
|
|
<label for="ical_sync_mode"><?php esc_html_e( 'Tryb synchronizacji iCal', 'yacht-booking' ); ?></label>
|
|
</th>
|
|
<td>
|
|
<select name="ical_sync_mode" id="ical_sync_mode">
|
|
<option value="per_yacht" <?php selected( $ical_sync_mode, 'per_yacht' ); ?>>
|
|
<?php esc_html_e( 'Per jacht — dopasowanie po prefiksie SUMMARY', 'yacht-booking' ); ?>
|
|
</option>
|
|
<option value="global" <?php selected( $ical_sync_mode, 'global' ); ?>>
|
|
<?php esc_html_e( 'Wspólny kalendarz — wszystkie eventy bez filtrowania', 'yacht-booking' ); ?>
|
|
</option>
|
|
</select>
|
|
<p class="description">
|
|
<?php esc_html_e( 'Per jacht: importowane są tylko eventy z prefiksem nazwy jachtu w tytule (format: "Nazwa jachtu - opis"). Eventy bez dopasowania są ignorowane. Tworzą blokady dostępności.', 'yacht-booking' ); ?>
|
|
</p>
|
|
<p class="description">
|
|
<?php esc_html_e( 'Wspólny kalendarz: importowane są wszystkie eventy bez wyjątku, jako wspólne wydarzenia kalendarza. NIE blokują dostępności poszczególnych jachtów. Pokazywane na widgecie zbiorczym "wszystkie jachty".', 'yacht-booking' ); ?>
|
|
</p>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row">
|
|
<label for="global_ical_import_url"><?php esc_html_e( 'iCal Import URL', 'yacht-booking' ); ?></label>
|
|
</th>
|
|
<td>
|
|
<input
|
|
type="url"
|
|
name="global_ical_import_url"
|
|
id="global_ical_import_url"
|
|
class="regular-text"
|
|
value="<?php echo esc_attr( $global_import_url ); ?>"
|
|
placeholder="https://calendar.google.com/calendar/ical/..."
|
|
style="width: 100%; max-width: 600px;"
|
|
/>
|
|
<?php if ( $last_global_run ) : ?>
|
|
<p class="description">
|
|
<?php
|
|
printf(
|
|
/* translators: %s: timestamp */
|
|
esc_html__( 'Ostatni import: %s', 'yacht-booking' ),
|
|
esc_html( $last_global_run )
|
|
);
|
|
?>
|
|
</p>
|
|
<?php endif; ?>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<p class="submit">
|
|
<input type="submit" name="yacht_booking_save_global_ical" class="button-primary" value="<?php esc_attr_e( 'Zapisz URL', 'yacht-booking' ); ?>">
|
|
</p>
|
|
</form>
|
|
|
|
<h4 style="margin-top: 25px;"><?php esc_html_e( 'Krok 3: Importuj teraz (opcjonalnie)', 'yacht-booking' ); ?></h4>
|
|
<p class="description">
|
|
<?php esc_html_e( 'Cron godzinny pobiera kalendarz automatycznie. Możesz wymusić import ręcznie:', 'yacht-booking' ); ?>
|
|
</p>
|
|
<form method="post" action="">
|
|
<?php wp_nonce_field( 'yacht_booking_run_global_ical_import' ); ?>
|
|
<button type="submit" name="yacht_booking_run_global_ical_import" class="button">
|
|
<?php esc_html_e( 'Importuj teraz', 'yacht-booking' ); ?>
|
|
</button>
|
|
</form>
|
|
|
|
<h4 style="margin-top: 25px;"><?php esc_html_e( 'Jak to działa', 'yacht-booking' ); ?></h4>
|
|
<ul style="margin-left: 20px; list-style: disc;">
|
|
<li><?php esc_html_e( 'Tytuły eventów w Google Calendar muszą mieć format: "Nazwa jachtu - dowolny opis" (separator to spacja-myślnik-spacja).', 'yacht-booking' ); ?></li>
|
|
<li><?php esc_html_e( 'Dopasowanie po pełnej nazwie jachtu lub jego aliasie (pole "Alias dla Google Calendar" w edycji jachtu).', 'yacht-booking' ); ?></li>
|
|
<li><?php esc_html_e( 'Eventy bez separatora albo z nieznanym prefiksem są ignorowane (nie tworzą blokad).', 'yacht-booking' ); ?></li>
|
|
<li><?php esc_html_e( 'Usunięcie eventu w Google Calendar usuwa odpowiadającą blokadę po następnym imporcie.', 'yacht-booking' ); ?></li>
|
|
<li><?php esc_html_e( 'Eventy zaimportowane z Google nie są wysyłane z powrotem (anti-loop).', 'yacht-booking' ); ?></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<?php
|
|
}
|
|
|
|
/**
|
|
* Save general settings
|
|
*/
|
|
private function save_settings() {
|
|
// Online booking toggle
|
|
update_option( 'yacht_booking_enabled', isset( $_POST['booking_enabled'] ) ? '1' : '0' );
|
|
|
|
// Booking settings
|
|
if ( isset( $_POST['default_status'] ) ) {
|
|
$default_status = sanitize_text_field( wp_unslash( $_POST['default_status'] ) );
|
|
if ( in_array( $default_status, array( 'pending', 'confirmed' ), true ) ) {
|
|
update_option( 'yacht_booking_default_status', $default_status );
|
|
}
|
|
}
|
|
|
|
// Email settings
|
|
if ( isset( $_POST['email_from_name'] ) ) {
|
|
update_option( 'yacht_booking_email_from_name', sanitize_text_field( wp_unslash( $_POST['email_from_name'] ) ) );
|
|
}
|
|
if ( isset( $_POST['email_from'] ) ) {
|
|
update_option( 'yacht_booking_email_from', sanitize_email( wp_unslash( $_POST['email_from'] ) ) );
|
|
}
|
|
|
|
// Formatting settings
|
|
if ( isset( $_POST['date_format'] ) ) {
|
|
$date_format = sanitize_text_field( wp_unslash( $_POST['date_format'] ) );
|
|
if ( in_array( $date_format, Settings::get_supported_date_formats(), true ) ) {
|
|
update_option( 'yacht_booking_date_format', $date_format );
|
|
}
|
|
}
|
|
if ( isset( $_POST['currency_symbol'] ) ) {
|
|
update_option( 'yacht_booking_currency_symbol', sanitize_text_field( wp_unslash( $_POST['currency_symbol'] ) ) );
|
|
}
|
|
|
|
// Terms page
|
|
if ( isset( $_POST['terms_page_id'] ) ) {
|
|
update_option( 'yacht_booking_terms_page_id', absint( $_POST['terms_page_id'] ) );
|
|
}
|
|
|
|
wp_safe_redirect( admin_url( 'admin.php?page=yacht-bookings-settings&tab=general&saved=1' ) );
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Process booking actions (approve, cancel, delete)
|
|
*/
|
|
public function process_booking_actions() {
|
|
// Check if we're on the bookings list page
|
|
if ( ! isset( $_GET['page'] ) || $_GET['page'] !== 'yacht-bookings-list' ) {
|
|
return;
|
|
}
|
|
|
|
if ( ! current_user_can( 'yacht_booking_manage_bookings' ) ) {
|
|
return;
|
|
}
|
|
|
|
// Single action: approve
|
|
if ( isset( $_GET['action'] ) && $_GET['action'] === 'approve' && isset( $_GET['booking'] ) ) {
|
|
$booking_id = (int) $_GET['booking'];
|
|
check_admin_referer( 'approve_booking_' . $booking_id );
|
|
|
|
Booking::update_status( $booking_id, 'confirmed' );
|
|
|
|
wp_safe_redirect(
|
|
add_query_arg(
|
|
array(
|
|
'page' => 'yacht-bookings-list',
|
|
'approved' => 1,
|
|
),
|
|
admin_url( 'admin.php' )
|
|
)
|
|
);
|
|
exit;
|
|
}
|
|
|
|
// Single action: cancel
|
|
if ( isset( $_GET['action'] ) && $_GET['action'] === 'cancel' && isset( $_GET['booking'] ) ) {
|
|
$booking_id = (int) $_GET['booking'];
|
|
check_admin_referer( 'cancel_booking_' . $booking_id );
|
|
|
|
// Update status to cancelled
|
|
Booking::update_status( $booking_id, 'cancelled' );
|
|
|
|
// Clear availability cache
|
|
Availability::clear_booking_availability( $booking_id );
|
|
|
|
wp_safe_redirect(
|
|
add_query_arg(
|
|
array(
|
|
'page' => 'yacht-bookings-list',
|
|
'cancelled' => 1,
|
|
),
|
|
admin_url( 'admin.php' )
|
|
)
|
|
);
|
|
exit;
|
|
}
|
|
|
|
// Single action: delete
|
|
if ( isset( $_GET['action'] ) && $_GET['action'] === 'delete' && isset( $_GET['booking'] ) ) {
|
|
$booking_id = (int) $_GET['booking'];
|
|
check_admin_referer( 'delete_booking_' . $booking_id );
|
|
|
|
// Clear availability cache
|
|
Availability::clear_booking_availability( $booking_id );
|
|
|
|
// Delete booking
|
|
wp_delete_post( $booking_id, true );
|
|
|
|
wp_safe_redirect(
|
|
add_query_arg(
|
|
array(
|
|
'page' => 'yacht-bookings-list',
|
|
'deleted' => 1,
|
|
),
|
|
admin_url( 'admin.php' )
|
|
)
|
|
);
|
|
exit;
|
|
}
|
|
|
|
// Bulk actions
|
|
if ( isset( $_POST['action'] ) && isset( $_POST['booking'] ) ) {
|
|
check_admin_referer( 'bulk-bookings' );
|
|
|
|
$booking_ids = array_map( 'intval', $_POST['booking'] );
|
|
$action = sanitize_text_field( wp_unslash( $_POST['action'] ) );
|
|
$count = 0;
|
|
|
|
switch ( $action ) {
|
|
case 'approve':
|
|
foreach ( $booking_ids as $booking_id ) {
|
|
$current_status = Booking::get_status( $booking_id );
|
|
if ( 'pending' === $current_status ) {
|
|
Booking::update_status( $booking_id, 'confirmed' );
|
|
$count++;
|
|
}
|
|
}
|
|
wp_safe_redirect(
|
|
add_query_arg(
|
|
array(
|
|
'page' => 'yacht-bookings-list',
|
|
'approved' => $count,
|
|
),
|
|
admin_url( 'admin.php' )
|
|
)
|
|
);
|
|
exit;
|
|
|
|
case 'cancel':
|
|
foreach ( $booking_ids as $booking_id ) {
|
|
$current_status = Booking::get_status( $booking_id );
|
|
if ( in_array( $current_status, array( 'pending', 'confirmed' ), true ) ) {
|
|
Booking::update_status( $booking_id, 'cancelled' );
|
|
Availability::clear_booking_availability( $booking_id );
|
|
$count++;
|
|
}
|
|
}
|
|
wp_safe_redirect(
|
|
add_query_arg(
|
|
array(
|
|
'page' => 'yacht-bookings-list',
|
|
'cancelled' => $count,
|
|
),
|
|
admin_url( 'admin.php' )
|
|
)
|
|
);
|
|
exit;
|
|
|
|
case 'delete':
|
|
foreach ( $booking_ids as $booking_id ) {
|
|
Availability::clear_booking_availability( $booking_id );
|
|
wp_delete_post( $booking_id, true );
|
|
$count++;
|
|
}
|
|
wp_safe_redirect(
|
|
add_query_arg(
|
|
array(
|
|
'page' => 'yacht-bookings-list',
|
|
'deleted' => $count,
|
|
),
|
|
admin_url( 'admin.php' )
|
|
)
|
|
);
|
|
exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send email notification to customer when booking status changes
|
|
*
|
|
* @param int $booking_id Booking post ID.
|
|
* @param string $new_status New status.
|
|
*/
|
|
public function send_customer_notification( $booking_id, $new_status ) {
|
|
// Only send emails for confirmed and cancelled statuses
|
|
if ( ! in_array( $new_status, array( 'confirmed', 'cancelled' ), true ) ) {
|
|
return;
|
|
}
|
|
|
|
$template_type = 'confirmed' === $new_status
|
|
? Email_Templates::TYPE_CUSTOMER_CONFIRMED
|
|
: Email_Templates::TYPE_CUSTOMER_CANCELLED;
|
|
$template_data = Email_Templates::get_booking_template_data( $booking_id );
|
|
$customer_email = Booking::get_customer_email( $booking_id );
|
|
$template = Email_Templates::compile( $template_type, $template_data );
|
|
|
|
if ( empty( $customer_email ) || empty( $template['subject'] ) ) {
|
|
return;
|
|
}
|
|
|
|
// Email headers
|
|
$headers = array(
|
|
'Content-Type: text/html; charset=UTF-8',
|
|
'From: ' . Settings::get_email_from_name() . ' <' . Settings::get_email_from_address() . '>',
|
|
);
|
|
|
|
// Send email
|
|
wp_mail( $customer_email, $template['subject'], $template['body'], $headers );
|
|
|
|
// Allow other plugins to hook in
|
|
do_action( 'yacht_booking_customer_notification_sent', $booking_id, $new_status, $customer_email );
|
|
}
|
|
}
|
|
|