first commit

This commit is contained in:
Roman Pyrih
2026-04-21 15:48:41 +02:00
commit 7483681901
10216 changed files with 3236626 additions and 0 deletions

View File

@@ -0,0 +1,255 @@
<?php
/**
* Availability Checker Class
*
* @package YachtBooking
*/
namespace YachtBooking;
// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Availability class - handles yacht availability checking and caching
*/
class Availability {
/**
* Check if yacht is available for given date range
*
* @param int $yacht_id Yacht post ID.
* @param string $start_date Start date (Y-m-d).
* @param string $end_date End date (Y-m-d).
* @return bool
*/
public static function is_available( $yacht_id, $start_date, $end_date ) {
global $wpdb;
$table = $wpdb->prefix . 'yacht_availability';
// Get all dates in range that are not available
$unavailable = $wpdb->get_var(
$wpdb->prepare(
"SELECT COUNT(*) FROM $table
WHERE yacht_id = %d
AND date >= %s
AND date < %s
AND status != 'available'",
$yacht_id,
$start_date,
$end_date
)
);
return 0 === (int) $unavailable;
}
/**
* Mark dates as booked
*
* @param int $yacht_id Yacht post ID.
* @param string $start_date Start date (Y-m-d).
* @param string $end_date End date (Y-m-d).
* @param int $booking_id Booking post ID.
* @return bool
*/
public static function mark_as_booked( $yacht_id, $start_date, $end_date, $booking_id ) {
global $wpdb;
$table = $wpdb->prefix . 'yacht_availability';
$dates = self::get_date_range( $start_date, $end_date );
foreach ( $dates as $date ) {
$wpdb->replace(
$table,
array(
'yacht_id' => $yacht_id,
'date' => $date,
'status' => 'booked',
'booking_id' => $booking_id,
'created_at' => current_time( 'mysql' ),
'updated_at' => current_time( 'mysql' ),
),
array( '%d', '%s', '%s', '%d', '%s', '%s' )
);
}
return true;
}
/**
* Mark dates as blocked (from Google Calendar sync)
*
* @param int $yacht_id Yacht post ID.
* @param string $start_date Start date (Y-m-d).
* @param string $end_date End date (Y-m-d).
* @return bool
*/
public static function mark_as_blocked( $yacht_id, $start_date, $end_date ) {
global $wpdb;
$table = $wpdb->prefix . 'yacht_availability';
$dates = self::get_date_range( $start_date, $end_date );
foreach ( $dates as $date ) {
$wpdb->replace(
$table,
array(
'yacht_id' => $yacht_id,
'date' => $date,
'status' => 'blocked',
'booking_id' => null,
'created_at' => current_time( 'mysql' ),
'updated_at' => current_time( 'mysql' ),
),
array( '%d', '%s', '%s', '%d', '%s', '%s' )
);
}
return true;
}
/**
* Mark dates as available (when booking is cancelled)
*
* @param int $yacht_id Yacht post ID.
* @param string $start_date Start date (Y-m-d).
* @param string $end_date End date (Y-m-d).
* @return bool
*/
public static function mark_as_available( $yacht_id, $start_date, $end_date ) {
global $wpdb;
$table = $wpdb->prefix . 'yacht_availability';
$wpdb->delete(
$table,
array(
'yacht_id' => $yacht_id,
),
array( '%d' )
);
// Alternative: update to available instead of delete
// $dates = self::get_date_range( $start_date, $end_date );
// foreach ( $dates as $date ) {
// $wpdb->update(
// $table,
// array( 'status' => 'available', 'booking_id' => null ),
// array( 'yacht_id' => $yacht_id, 'date' => $date ),
// array( '%s', '%d' ),
// array( '%d', '%s' )
// );
// }
return true;
}
/**
* Clear availability for booking
*
* @param int $booking_id Booking post ID.
* @return bool
*/
public static function clear_booking_availability( $booking_id ) {
global $wpdb;
$table = $wpdb->prefix . 'yacht_availability';
$wpdb->delete(
$table,
array( 'booking_id' => $booking_id ),
array( '%d' )
);
return true;
}
/**
* Get availability calendar for yacht and month
*
* @param int $yacht_id Yacht post ID.
* @param string $start Start date (Y-m-d).
* @param string $end End date (Y-m-d).
* @return array
*/
public static function get_availability_calendar( $yacht_id, $start, $end ) {
global $wpdb;
$table = $wpdb->prefix . 'yacht_availability';
$results = $wpdb->get_results(
$wpdb->prepare(
"SELECT date, status, booking_id FROM $table
WHERE yacht_id = %d
AND date >= %s
AND date <= %s
ORDER BY date ASC",
$yacht_id,
$start,
$end
),
ARRAY_A
);
// Create associative array with date as key
$calendar = array();
foreach ( $results as $row ) {
$calendar[ $row['date'] ] = array(
'status' => $row['status'],
'booking_id' => $row['booking_id'],
);
}
// Fill in missing dates as available
$all_dates = self::get_date_range( $start, $end );
foreach ( $all_dates as $date ) {
if ( ! isset( $calendar[ $date ] ) ) {
$calendar[ $date ] = array(
'status' => 'available',
'booking_id' => null,
);
}
}
return $calendar;
}
/**
* Count days between two dates
*
* @param string $start_date Start date (Y-m-d).
* @param string $end_date End date (Y-m-d).
* @return int
*/
public static function count_days( $start_date, $end_date ) {
$start = new \DateTime( $start_date );
$end = new \DateTime( $end_date );
$diff = $start->diff( $end );
return (int) $diff->days;
}
/**
* Get array of dates between start and end (exclusive of end date)
*
* @param string $start_date Start date (Y-m-d).
* @param string $end_date End date (Y-m-d).
* @return array
*/
private static function get_date_range( $start_date, $end_date ) {
$dates = array();
$start = new \DateTime( $start_date );
$end = new \DateTime( $end_date );
while ( $start < $end ) {
$dates[] = $start->format( 'Y-m-d' );
$start->modify( '+1 day' );
}
return $dates;
}
}

View File

@@ -0,0 +1,249 @@
<?php
/**
* Booking Custom Post Type
*
* @package YachtBooking
*/
namespace YachtBooking;
// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Booking CPT class
*/
class Booking {
/**
* Register custom post type
*/
public static function register() {
$labels = array(
'name' => __( 'Rezerwacje', 'yacht-booking' ),
'singular_name' => __( 'Rezerwacja', 'yacht-booking' ),
'menu_name' => __( 'Rezerwacje', 'yacht-booking' ),
'name_admin_bar' => __( 'Rezerwacja', 'yacht-booking' ),
'add_new' => __( 'Dodaj nową', 'yacht-booking' ),
'add_new_item' => __( 'Dodaj nową rezerwację', 'yacht-booking' ),
'new_item' => __( 'Nowa rezerwacja', 'yacht-booking' ),
'edit_item' => __( 'Edytuj rezerwację', 'yacht-booking' ),
'view_item' => __( 'Zobacz rezerwację', 'yacht-booking' ),
'all_items' => __( 'Wszystkie rezerwacje', 'yacht-booking' ),
'search_items' => __( 'Szukaj rezerwacji', 'yacht-booking' ),
'parent_item_colon' => __( 'Nadrzędna rezerwacja:', 'yacht-booking' ),
'not_found' => __( 'Nie znaleziono rezerwacji', 'yacht-booking' ),
'not_found_in_trash' => __( 'Nie znaleziono rezerwacji w koszu', 'yacht-booking' ),
);
$args = array(
'labels' => $labels,
'description' => __( 'Rezerwacje jachtów', 'yacht-booking' ),
'public' => false,
'publicly_queryable' => false,
'show_ui' => true,
'show_in_menu' => false, // Custom menu będzie w class-admin.php
'show_in_rest' => true,
'query_var' => true,
'rewrite' => false,
'capability_type' => 'post',
'capabilities' => array(
'edit_post' => 'yacht_booking_manage_bookings',
'read_post' => 'yacht_booking_manage_bookings',
'delete_post' => 'yacht_booking_manage_bookings',
'edit_posts' => 'yacht_booking_manage_bookings',
'edit_others_posts' => 'yacht_booking_manage_bookings',
'publish_posts' => 'yacht_booking_manage_bookings',
'read_private_posts' => 'yacht_booking_manage_bookings',
'delete_posts' => 'yacht_booking_manage_bookings',
),
'has_archive' => false,
'hierarchical' => false,
'menu_position' => null,
'supports' => array( 'title', 'custom-fields' ),
);
register_post_type( 'yacht_booking', $args );
}
/**
* Get booking yacht ID
*
* @param int $booking_id Booking post ID.
* @return int
*/
public static function get_yacht_id( $booking_id ) {
return (int) get_post_meta( $booking_id, '_booking_yacht_id', true );
}
/**
* Get booking start date
*
* @param int $booking_id Booking post ID.
* @return string
*/
public static function get_start_date( $booking_id ) {
return get_post_meta( $booking_id, '_booking_start_date', true );
}
/**
* Get booking end date
*
* @param int $booking_id Booking post ID.
* @return string
*/
public static function get_end_date( $booking_id ) {
return get_post_meta( $booking_id, '_booking_end_date', true );
}
/**
* Get booking status
*
* @param int $booking_id Booking post ID.
* @return string
*/
public static function get_status( $booking_id ) {
$status = get_post_meta( $booking_id, '_booking_status', true );
return $status ? $status : 'pending';
}
/**
* Get customer name
*
* @param int $booking_id Booking post ID.
* @return string
*/
public static function get_customer_name( $booking_id ) {
return get_post_meta( $booking_id, '_booking_customer_name', true );
}
/**
* Get customer email
*
* @param int $booking_id Booking post ID.
* @return string
*/
public static function get_customer_email( $booking_id ) {
return get_post_meta( $booking_id, '_booking_customer_email', true );
}
/**
* Get customer phone
*
* @param int $booking_id Booking post ID.
* @return string
*/
public static function get_customer_phone( $booking_id ) {
return get_post_meta( $booking_id, '_booking_customer_phone', true );
}
/**
* Get total price
*
* @param int $booking_id Booking post ID.
* @return float
*/
public static function get_total_price( $booking_id ) {
return (float) get_post_meta( $booking_id, '_booking_total_price', true );
}
/**
* Get Google Calendar Event ID
*
* @param int $booking_id Booking post ID.
* @return string
*/
public static function get_gcal_event_id( $booking_id ) {
return get_post_meta( $booking_id, '_booking_gcal_event_id', true );
}
/**
* Get admin notes
*
* @param int $booking_id Booking post ID.
* @return string
*/
public static function get_notes( $booking_id ) {
return get_post_meta( $booking_id, '_booking_notes', true );
}
/**
* Update booking status
*
* @param int $booking_id Booking post ID.
* @param string $status Status (pending, confirmed, cancelled).
*/
public static function update_status( $booking_id, $status ) {
$valid_statuses = array( 'pending', 'confirmed', 'cancelled' );
if ( in_array( $status, $valid_statuses, true ) ) {
update_post_meta( $booking_id, '_booking_status', $status );
// Trigger action hook
do_action( 'yacht_booking_status_changed', $booking_id, $status );
}
}
/**
* Create new booking
*
* @param array $data Booking data.
* @return int|false Booking ID on success, false on failure.
*/
public static function create( $data ) {
// Validate required fields
$required = array( 'yacht_id', 'start_date', 'end_date', 'customer_name', 'customer_email', 'customer_phone' );
foreach ( $required as $field ) {
if ( empty( $data[ $field ] ) ) {
return false;
}
}
// Get yacht title
$yacht = get_post( $data['yacht_id'] );
if ( ! $yacht || $yacht->post_type !== 'yacht' ) {
return false;
}
// Create booking post
$booking_id = wp_insert_post(
array(
'post_type' => 'yacht_booking',
'post_title' => sprintf(
__( 'Rezerwacja #%s - %s', 'yacht-booking' ),
time(),
$yacht->post_title
),
'post_status' => 'publish',
)
);
if ( is_wp_error( $booking_id ) ) {
return false;
}
// Save booking meta
update_post_meta( $booking_id, '_booking_yacht_id', (int) $data['yacht_id'] );
update_post_meta( $booking_id, '_booking_start_date', sanitize_text_field( $data['start_date'] ) );
update_post_meta( $booking_id, '_booking_end_date', sanitize_text_field( $data['end_date'] ) );
update_post_meta( $booking_id, '_booking_status', ! empty( $data['status'] ) ? $data['status'] : 'pending' );
update_post_meta( $booking_id, '_booking_customer_name', sanitize_text_field( $data['customer_name'] ) );
update_post_meta( $booking_id, '_booking_customer_email', sanitize_email( $data['customer_email'] ) );
update_post_meta( $booking_id, '_booking_customer_phone', sanitize_text_field( $data['customer_phone'] ) );
if ( ! empty( $data['total_price'] ) ) {
update_post_meta( $booking_id, '_booking_total_price', (float) $data['total_price'] );
}
if ( ! empty( $data['notes'] ) ) {
update_post_meta( $booking_id, '_booking_notes', wp_kses_post( $data['notes'] ) );
}
// Trigger action hook
do_action( 'yacht_booking_created', $booking_id );
return $booking_id;
}
}

View File

@@ -0,0 +1,292 @@
<?php
/**
* Email templates helper.
*
* @package YachtBooking
*/
namespace YachtBooking;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Email templates class.
*/
class Email_Templates {
/**
* Option key.
*/
const OPTION_KEY = 'yacht_booking_email_templates';
/**
* Template type: admin notification.
*/
const TYPE_ADMIN_NEW_BOOKING = 'admin_new_booking';
/**
* Template type: customer confirmed.
*/
const TYPE_CUSTOMER_CONFIRMED = 'customer_confirmed';
/**
* Template type: customer cancelled.
*/
const TYPE_CUSTOMER_CANCELLED = 'customer_cancelled';
/**
* Get template labels.
*
* @return array
*/
public static function get_template_labels() {
return array(
self::TYPE_ADMIN_NEW_BOOKING => __( 'Nowa rezerwacja (email do admina)', 'yacht-booking' ),
self::TYPE_CUSTOMER_CONFIRMED => __( 'Potwierdzenie rezerwacji (email do klienta)', 'yacht-booking' ),
self::TYPE_CUSTOMER_CANCELLED => __( 'Anulowanie rezerwacji (email do klienta)', 'yacht-booking' ),
);
}
/**
* Get available tags for templates.
*
* @return array
*/
public static function get_available_tags() {
return array(
'{booking_id}' => __( 'ID rezerwacji', 'yacht-booking' ),
'{yacht_name}' => __( 'Nazwa jachtu', 'yacht-booking' ),
'{customer_name}' => __( 'Imię i nazwisko klienta', 'yacht-booking' ),
'{customer_email}' => __( 'Email klienta', 'yacht-booking' ),
'{customer_phone}' => __( 'Telefon klienta', 'yacht-booking' ),
'{start_date}' => __( 'Data rozpoczęcia', 'yacht-booking' ),
'{end_date}' => __( 'Data zakończenia', 'yacht-booking' ),
'{days}' => __( 'Liczba dni', 'yacht-booking' ),
'{total_price}' => __( 'Cena całkowita', 'yacht-booking' ),
'{status}' => __( 'Status rezerwacji', 'yacht-booking' ),
'{admin_link}' => __( 'Link do panelu admin', 'yacht-booking' ),
'{site_name}' => __( 'Nazwa strony', 'yacht-booking' ),
);
}
/**
* Get default templates.
*
* @return array
*/
public static function get_default_templates() {
return array(
self::TYPE_ADMIN_NEW_BOOKING => array(
'subject' => __( '[Nowa Rezerwacja] #{booking_id} - {site_name}', 'yacht-booking' ),
'body' => __(
'<p>Otrzymano nową rezerwację jachtu.</p>
<p><strong>Szczegóły rezerwacji:</strong><br>
Numer rezerwacji: #{booking_id}<br>
Jacht: {yacht_name}<br>
Data rozpoczęcia: {start_date}<br>
Data zakończenia: {end_date}<br>
Liczba dni: {days}<br>
Cena całkowita: {total_price}<br>
Status: {status}</p>
<p><strong>Dane klienta:</strong><br>
Imię i nazwisko: {customer_name}<br>
Email: {customer_email}<br>
Telefon: {customer_phone}</p>
<p><a href="{admin_link}">Przejdź do zarządzania rezerwacją</a></p>',
'yacht-booking'
),
),
self::TYPE_CUSTOMER_CONFIRMED => array(
'subject' => __( '[Potwierdzenie] Rezerwacja #{booking_id} - {site_name}', 'yacht-booking' ),
'body' => __(
'<p>Witaj {customer_name},</p>
<p>Twoja rezerwacja jachtu została potwierdzona.</p>
<p><strong>Szczegóły rezerwacji:</strong><br>
Numer rezerwacji: #{booking_id}<br>
Jacht: {yacht_name}<br>
Data rozpoczęcia: {start_date}<br>
Data zakończenia: {end_date}<br>
Liczba dni: {days}<br>
Cena całkowita: {total_price}</p>
<p>Dziękujemy za wybranie naszych usług.</p>',
'yacht-booking'
),
),
self::TYPE_CUSTOMER_CANCELLED => array(
'subject' => __( '[Anulowanie] Rezerwacja #{booking_id} - {site_name}', 'yacht-booking' ),
'body' => __(
'<p>Witaj {customer_name},</p>
<p>Niestety Twoja rezerwacja jachtu została anulowana.</p>
<p><strong>Szczegóły rezerwacji:</strong><br>
Numer rezerwacji: #{booking_id}<br>
Jacht: {yacht_name}<br>
Data rozpoczęcia: {start_date}<br>
Data zakończenia: {end_date}</p>
<p>W razie pytań prosimy o kontakt.</p>',
'yacht-booking'
),
),
);
}
/**
* Get all templates.
*
* @return array
*/
public static function get_templates() {
$defaults = self::get_default_templates();
$saved = get_option( self::OPTION_KEY, array() );
if ( ! is_array( $saved ) ) {
return $defaults;
}
$merged = array();
foreach ( $defaults as $type => $template ) {
$merged[ $type ] = array(
'subject' => isset( $saved[ $type ]['subject'] ) && '' !== trim( (string) $saved[ $type ]['subject'] )
? sanitize_text_field( $saved[ $type ]['subject'] )
: $template['subject'],
'body' => isset( $saved[ $type ]['body'] ) && '' !== trim( (string) $saved[ $type ]['body'] )
? wp_kses_post( $saved[ $type ]['body'] )
: $template['body'],
);
}
return $merged;
}
/**
* Save templates.
*
* @param array $templates Templates.
* @return bool
*/
public static function save_templates( $templates ) {
$defaults = self::get_default_templates();
$normalized = array();
foreach ( $defaults as $type => $default_template ) {
$subject = isset( $templates[ $type ]['subject'] ) ? sanitize_text_field( wp_unslash( $templates[ $type ]['subject'] ) ) : '';
$body = isset( $templates[ $type ]['body'] ) ? wp_kses_post( wp_unslash( $templates[ $type ]['body'] ) ) : '';
$normalized[ $type ] = array(
'subject' => '' !== trim( $subject ) ? $subject : $default_template['subject'],
'body' => '' !== trim( $body ) ? $body : $default_template['body'],
);
}
return update_option( self::OPTION_KEY, $normalized );
}
/**
* Reset to default templates.
*
* @return bool
*/
public static function reset_templates() {
return delete_option( self::OPTION_KEY );
}
/**
* Compile template with replacement tags.
*
* @param string $type Template type.
* @param array $data Data for replacements.
* @return array
*/
public static function compile( $type, $data = array() ) {
$templates = self::get_templates();
if ( ! isset( $templates[ $type ] ) ) {
return array(
'subject' => '',
'body' => '',
);
}
$replacements = self::build_replacements( $data );
return array(
'subject' => strtr( $templates[ $type ]['subject'], $replacements ),
'body' => strtr( $templates[ $type ]['body'], $replacements ),
);
}
/**
* Build replacement map.
*
* @param array $data Raw data.
* @return array
*/
private static function build_replacements( $data ) {
$site_name = get_bloginfo( 'name' );
return array(
'{booking_id}' => isset( $data['booking_id'] ) ? (string) $data['booking_id'] : '',
'{yacht_name}' => isset( $data['yacht_name'] ) ? (string) $data['yacht_name'] : '',
'{customer_name}' => isset( $data['customer_name'] ) ? (string) $data['customer_name'] : '',
'{customer_email}' => isset( $data['customer_email'] ) ? (string) $data['customer_email'] : '',
'{customer_phone}' => isset( $data['customer_phone'] ) ? (string) $data['customer_phone'] : '',
'{start_date}' => isset( $data['start_date'] ) ? (string) $data['start_date'] : '',
'{end_date}' => isset( $data['end_date'] ) ? (string) $data['end_date'] : '',
'{days}' => isset( $data['days'] ) ? (string) $data['days'] : '',
'{total_price}' => isset( $data['total_price'] ) ? (string) $data['total_price'] : '',
'{status}' => isset( $data['status'] ) ? (string) $data['status'] : '',
'{admin_link}' => isset( $data['admin_link'] ) ? (string) $data['admin_link'] : '',
'{site_name}' => $site_name,
);
}
/**
* Build booking data for template replacements.
*
* @param int $booking_id Booking ID.
* @return array
*/
public static function get_booking_template_data( $booking_id ) {
$booking_id = absint( $booking_id );
$yacht_id = Booking::get_yacht_id( $booking_id );
$yacht = get_post( $yacht_id );
$start_date = Booking::get_start_date( $booking_id );
$end_date = Booking::get_end_date( $booking_id );
$status = Booking::get_status( $booking_id );
$days = Availability::count_days( $start_date, $end_date );
return array(
'booking_id' => $booking_id,
'yacht_name' => $yacht ? $yacht->post_title : __( 'Nieznany', 'yacht-booking' ),
'customer_name' => Booking::get_customer_name( $booking_id ),
'customer_email' => Booking::get_customer_email( $booking_id ),
'customer_phone' => Booking::get_customer_phone( $booking_id ),
'start_date' => Settings::format_date( $start_date ),
'end_date' => Settings::format_date( $end_date ),
'days' => $days,
'total_price' => Settings::format_price( Booking::get_total_price( $booking_id ) ),
'status' => self::get_status_label( $status ),
'admin_link' => admin_url( 'admin.php?page=yacht-bookings-list&booking_id=' . $booking_id ),
);
}
/**
* Get localized status label.
*
* @param string $status Status.
* @return string
*/
private static function get_status_label( $status ) {
$labels = array(
'pending' => __( 'Oczekująca', 'yacht-booking' ),
'confirmed' => __( 'Potwierdzona', 'yacht-booking' ),
'cancelled' => __( 'Anulowana', 'yacht-booking' ),
);
return isset( $labels[ $status ] ) ? $labels[ $status ] : $status;
}
}

View File

@@ -0,0 +1,264 @@
<?php
/**
* Inquiry Custom Post Type
*
* @package YachtBooking
*/
namespace YachtBooking;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Inquiry CPT class
*/
class Inquiry {
/**
* Register custom post type
*/
public static function register() {
register_post_type(
'yacht_inquiry',
array(
'labels' => array(
'name' => __( 'Zapytania', 'yacht-booking' ),
'singular_name' => __( 'Zapytanie', 'yacht-booking' ),
),
'public' => false,
'publicly_queryable' => false,
'show_ui' => false,
'show_in_menu' => false,
'show_in_rest' => false,
'capability_type' => 'post',
'capabilities' => array(
'edit_post' => 'yacht_booking_manage_bookings',
'read_post' => 'yacht_booking_manage_bookings',
'delete_post' => 'yacht_booking_manage_bookings',
'edit_posts' => 'yacht_booking_manage_bookings',
'edit_others_posts' => 'yacht_booking_manage_bookings',
'publish_posts' => 'yacht_booking_manage_bookings',
'read_private_posts' => 'yacht_booking_manage_bookings',
'delete_posts' => 'yacht_booking_manage_bookings',
),
'has_archive' => false,
'supports' => array( 'title', 'custom-fields' ),
)
);
}
/**
* Get yacht ID.
*
* @param int $inquiry_id Inquiry post ID.
* @return int
*/
public static function get_yacht_id( $inquiry_id ) {
return (int) get_post_meta( $inquiry_id, '_inquiry_yacht_id', true );
}
/**
* Get customer name.
*
* @param int $inquiry_id Inquiry post ID.
* @return string
*/
public static function get_customer_name( $inquiry_id ) {
return get_post_meta( $inquiry_id, '_inquiry_customer_name', true );
}
/**
* Get customer email.
*
* @param int $inquiry_id Inquiry post ID.
* @return string
*/
public static function get_customer_email( $inquiry_id ) {
return get_post_meta( $inquiry_id, '_inquiry_customer_email', true );
}
/**
* Get customer phone.
*
* @param int $inquiry_id Inquiry post ID.
* @return string
*/
public static function get_customer_phone( $inquiry_id ) {
return get_post_meta( $inquiry_id, '_inquiry_customer_phone', true );
}
/**
* Get message.
*
* @param int $inquiry_id Inquiry post ID.
* @return string
*/
public static function get_message( $inquiry_id ) {
return get_post_meta( $inquiry_id, '_inquiry_message', true );
}
/**
* Get preferred dates.
*
* @param int $inquiry_id Inquiry post ID.
* @return string
*/
public static function get_preferred_dates( $inquiry_id ) {
return get_post_meta( $inquiry_id, '_inquiry_preferred_dates', true );
}
/**
* Get email sent to admin body.
*
* @param int $inquiry_id Inquiry post ID.
* @return string
*/
public static function get_admin_email_body( $inquiry_id ) {
return get_post_meta( $inquiry_id, '_inquiry_admin_email_body', true );
}
/**
* Get email sent to customer body.
*
* @param int $inquiry_id Inquiry post ID.
* @return string
*/
public static function get_customer_email_body( $inquiry_id ) {
return get_post_meta( $inquiry_id, '_inquiry_customer_email_body', true );
}
/**
* Create new inquiry.
*
* @param array $data Inquiry data.
* @return int|false Inquiry ID on success, false on failure.
*/
public static function create( $data ) {
$required = array( 'yacht_id', 'customer_name', 'customer_email', 'customer_phone' );
foreach ( $required as $field ) {
if ( empty( $data[ $field ] ) ) {
return false;
}
}
$yacht = get_post( $data['yacht_id'] );
if ( ! $yacht || 'yacht' !== $yacht->post_type ) {
return false;
}
$inquiry_id = wp_insert_post(
array(
'post_type' => 'yacht_inquiry',
'post_title' => sprintf(
__( 'Zapytanie #%s - %s', 'yacht-booking' ),
time(),
$yacht->post_title
),
'post_status' => 'publish',
)
);
if ( is_wp_error( $inquiry_id ) ) {
return false;
}
update_post_meta( $inquiry_id, '_inquiry_yacht_id', (int) $data['yacht_id'] );
update_post_meta( $inquiry_id, '_inquiry_customer_name', sanitize_text_field( $data['customer_name'] ) );
update_post_meta( $inquiry_id, '_inquiry_customer_email', sanitize_email( $data['customer_email'] ) );
update_post_meta( $inquiry_id, '_inquiry_customer_phone', sanitize_text_field( $data['customer_phone'] ) );
if ( ! empty( $data['message'] ) ) {
update_post_meta( $inquiry_id, '_inquiry_message', sanitize_textarea_field( $data['message'] ) );
}
if ( ! empty( $data['preferred_dates'] ) ) {
update_post_meta( $inquiry_id, '_inquiry_preferred_dates', sanitize_text_field( $data['preferred_dates'] ) );
}
return $inquiry_id;
}
/**
* Send inquiry emails (admin + customer) and store copies.
*
* @param int $inquiry_id Inquiry ID.
*/
public static function send_emails( $inquiry_id ) {
$inquiry_id = absint( $inquiry_id );
$yacht_id = self::get_yacht_id( $inquiry_id );
$yacht = get_post( $yacht_id );
$yacht_name = $yacht ? $yacht->post_title : __( 'Nieznany', 'yacht-booking' );
$customer_name = self::get_customer_name( $inquiry_id );
$customer_email = self::get_customer_email( $inquiry_id );
$customer_phone = self::get_customer_phone( $inquiry_id );
$message = self::get_message( $inquiry_id );
$preferred_dates = self::get_preferred_dates( $inquiry_id );
$site_name = get_bloginfo( 'name' );
$from_name = Settings::get_email_from_name();
$from_address = Settings::get_email_from_address();
$headers = array(
'Content-Type: text/html; charset=UTF-8',
'From: ' . $from_name . ' <' . $from_address . '>',
);
// --- Admin email ---
$admin_subject = sprintf(
/* translators: 1: inquiry ID, 2: site name */
__( '[Zapytanie o rezerwację] #%1$d - %2$s', 'yacht-booking' ),
$inquiry_id,
$site_name
);
$admin_body = '<p>' . __( 'Otrzymano nowe zapytanie o rezerwację jachtu.', 'yacht-booking' ) . '</p>';
$admin_body .= '<p><strong>' . __( 'Jacht:', 'yacht-booking' ) . '</strong> ' . esc_html( $yacht_name ) . '</p>';
if ( $preferred_dates ) {
$admin_body .= '<p><strong>' . __( 'Preferowane terminy:', 'yacht-booking' ) . '</strong> ' . esc_html( $preferred_dates ) . '</p>';
}
$admin_body .= '<p><strong>' . __( 'Dane klienta:', 'yacht-booking' ) . '</strong><br>';
$admin_body .= esc_html__( 'Imię i nazwisko:', 'yacht-booking' ) . ' ' . esc_html( $customer_name ) . '<br>';
$admin_body .= esc_html__( 'Email:', 'yacht-booking' ) . ' ' . esc_html( $customer_email ) . '<br>';
$admin_body .= esc_html__( 'Telefon:', 'yacht-booking' ) . ' ' . esc_html( $customer_phone ) . '</p>';
if ( $message ) {
$admin_body .= '<p><strong>' . __( 'Wiadomość:', 'yacht-booking' ) . '</strong><br>' . nl2br( esc_html( $message ) ) . '</p>';
}
$admin_body .= '<p><a href="' . esc_url( admin_url( 'admin.php?page=yacht-inquiries' ) ) . '">'
. __( 'Przejdź do listy zapytań', 'yacht-booking' ) . '</a></p>';
$admin_headers = $headers;
$admin_headers[] = 'Reply-To: ' . $customer_name . ' <' . $customer_email . '>';
wp_mail( get_option( 'admin_email' ), $admin_subject, $admin_body, $admin_headers );
update_post_meta( $inquiry_id, '_inquiry_admin_email_body', $admin_body );
// --- Customer confirmation email ---
$customer_subject = sprintf(
/* translators: 1: site name */
__( 'Potwierdzenie zapytania o rezerwację - %s', 'yacht-booking' ),
$site_name
);
$customer_body = '<p>' . sprintf(
/* translators: %s: customer name */
__( 'Witaj %s,', 'yacht-booking' ),
esc_html( $customer_name )
) . '</p>';
$customer_body .= '<p>' . __( 'Dziękujemy za przesłanie zapytania o rezerwację jachtu. Otrzymaliśmy Twoje zgłoszenie i skontaktujemy się z Tobą najszybciej jak to możliwe.', 'yacht-booking' ) . '</p>';
$customer_body .= '<p><strong>' . __( 'Szczegóły zapytania:', 'yacht-booking' ) . '</strong><br>';
$customer_body .= esc_html__( 'Jacht:', 'yacht-booking' ) . ' ' . esc_html( $yacht_name ) . '</p>';
if ( $preferred_dates ) {
$customer_body .= '<p>' . esc_html__( 'Preferowane terminy:', 'yacht-booking' ) . ' ' . esc_html( $preferred_dates ) . '</p>';
}
if ( $message ) {
$customer_body .= '<p>' . esc_html__( 'Twoja wiadomość:', 'yacht-booking' ) . '<br>' . nl2br( esc_html( $message ) ) . '</p>';
}
$customer_body .= '<p>' . __( 'Pozdrawiamy,', 'yacht-booking' ) . '<br>' . esc_html( $site_name ) . '</p>';
wp_mail( $customer_email, $customer_subject, $customer_body, $headers );
update_post_meta( $inquiry_id, '_inquiry_customer_email_body', $customer_body );
}
}

View File

@@ -0,0 +1,87 @@
<?php
/**
* Plugin Installer Class
*
* @package YachtBooking
*/
namespace YachtBooking;
// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Installer class - handles plugin installation and database setup
*/
class Installer {
/**
* Run installation
*/
public function install() {
$this->create_tables();
$this->create_options();
$this->set_version();
}
/**
* Create custom database tables
*/
private function create_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$table_name = $wpdb->prefix . 'yacht_availability';
$sql = "CREATE TABLE $table_name (
id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
yacht_id bigint(20) UNSIGNED NOT NULL,
date date NOT NULL,
status varchar(20) NOT NULL DEFAULT 'available',
booking_id bigint(20) UNSIGNED NULL,
created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY yacht_date (yacht_id, date),
KEY yacht_id (yacht_id),
KEY date (date),
KEY status (status),
KEY booking_id (booking_id)
) $charset_collate;";
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta( $sql );
}
/**
* Create default plugin options
*/
private function create_options() {
$options = array(
'yacht_booking_default_status' => 'pending',
'yacht_booking_email_from_name' => get_bloginfo( 'name' ),
'yacht_booking_email_from' => get_bloginfo( 'admin_email' ),
'yacht_booking_date_format' => 'Y-m-d',
'yacht_booking_currency_symbol' => 'zł',
'yacht_booking_terms_page_id' => 0,
'yacht_booking_enable_notifications' => 'yes',
'yacht_booking_gcal_sync_enabled' => 'no',
);
foreach ( $options as $key => $value ) {
if ( false === get_option( $key ) ) {
add_option( $key, $value );
}
}
}
/**
* Set plugin version
*/
private function set_version() {
update_option( 'yacht_booking_version', YACHT_BOOKING_VERSION );
update_option( 'yacht_booking_installed_at', current_time( 'mysql' ) );
}
}

View File

@@ -0,0 +1,140 @@
<?php
/**
* Plugin settings helper.
*
* @package YachtBooking
*/
namespace YachtBooking;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Settings helper class.
*/
class Settings {
/**
* Check if online booking is enabled.
*
* @return bool
*/
public static function is_booking_enabled() {
return '1' === get_option( 'yacht_booking_enabled', '1' );
}
/**
* Get default booking status.
*
* @return string
*/
public static function get_default_status() {
$status = get_option( 'yacht_booking_default_status', 'pending' );
return in_array( $status, array( 'pending', 'confirmed' ), true ) ? $status : 'pending';
}
/**
* Get email from name.
*
* @return string
*/
public static function get_email_from_name() {
$value = get_option( 'yacht_booking_email_from_name', get_bloginfo( 'name' ) );
return is_string( $value ) && '' !== $value ? $value : get_bloginfo( 'name' );
}
/**
* Get email from address.
*
* @return string
*/
public static function get_email_from_address() {
$value = get_option( 'yacht_booking_email_from', '' );
// Backward compatibility with older option name.
if ( empty( $value ) ) {
$value = get_option( 'yacht_booking_email_from_address', get_option( 'admin_email' ) );
}
return is_email( $value ) ? $value : get_option( 'admin_email' );
}
/**
* Get supported date formats.
*
* @return array
*/
public static function get_supported_date_formats() {
return array( 'Y-m-d', 'd/m/Y', 'm/d/Y', 'd.m.Y' );
}
/**
* Get date format.
*
* @return string
*/
public static function get_date_format() {
$format = get_option( 'yacht_booking_date_format', 'Y-m-d' );
return in_array( $format, self::get_supported_date_formats(), true ) ? $format : 'Y-m-d';
}
/**
* Format date using plugin settings.
*
* @param string $date Date string.
* @return string
*/
public static function format_date( $date ) {
$timestamp = strtotime( (string) $date );
return false !== $timestamp ? date_i18n( self::get_date_format(), $timestamp ) : '';
}
/**
* Get currency symbol.
*
* @return string
*/
public static function get_currency_symbol() {
$symbol = get_option( 'yacht_booking_currency_symbol', 'zł' );
$symbol = is_string( $symbol ) ? trim( $symbol ) : '';
return '' !== $symbol ? $symbol : 'zł';
}
/**
* Format price using plugin settings.
*
* @param float $amount Amount.
* @return string
*/
public static function format_price( $amount ) {
return trim( number_format_i18n( (float) $amount, 2 ) . ' ' . self::get_currency_symbol() );
}
/**
* Get terms page ID.
*
* @return int
*/
public static function get_terms_page_id() {
return absint( get_option( 'yacht_booking_terms_page_id', 0 ) );
}
/**
* Get terms page URL.
*
* @return string
*/
public static function get_terms_page_url() {
$page_id = self::get_terms_page_id();
if ( ! $page_id ) {
return '';
}
$url = get_permalink( $page_id );
return $url ? $url : '';
}
}

View File

@@ -0,0 +1,353 @@
<?php
/**
* Main Plugin Class
*
* @package YachtBooking
*/
namespace YachtBooking;
// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Main Yacht Booking class - Singleton pattern
*/
class Yacht_Booking {
/**
* Single instance of the class
*
* @var Yacht_Booking
*/
private static $instance = null;
/**
* Get instance
*
* @return Yacht_Booking
*/
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor
*/
private function __construct() {
$this->init_hooks();
$this->load_dependencies();
}
/**
* Initialize WordPress hooks
*/
private function init_hooks() {
// Register Custom Post Types
add_action( 'init', array( $this, 'register_post_types' ), 10 );
// Enqueue scripts and styles
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_frontend_assets' ), 10 );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ), 10 );
// Register REST API routes
add_action( 'rest_api_init', array( $this, 'register_rest_routes' ), 10 );
// Register Elementor widgets
add_action( 'elementor/widgets/register', array( $this, 'register_elementor_widgets' ), 10 );
// Register shortcodes
add_action( 'init', array( $this, 'register_shortcodes' ), 15 );
// Add custom capabilities
add_action( 'admin_init', array( $this, 'add_custom_capabilities' ), 10 );
}
/**
* Load plugin dependencies
*/
private function load_dependencies() {
// Load CPT handlers
require_once YACHT_BOOKING_PLUGIN_DIR . 'includes/class-yacht.php';
require_once YACHT_BOOKING_PLUGIN_DIR . 'includes/class-booking.php';
require_once YACHT_BOOKING_PLUGIN_DIR . 'includes/class-availability.php';
// Load admin classes
if ( is_admin() ) {
require_once YACHT_BOOKING_PLUGIN_DIR . 'admin/class-admin.php';
Admin::get_instance();
}
// Load Google Calendar integration
require_once YACHT_BOOKING_PLUGIN_DIR . 'integrations/google-calendar/class-oauth-handler.php';
require_once YACHT_BOOKING_PLUGIN_DIR . 'integrations/google-calendar/class-gcal-service.php';
require_once YACHT_BOOKING_PLUGIN_DIR . 'integrations/google-calendar/class-sync-controller.php';
// Initialize sync controller
\YachtBooking\Integrations\GoogleCalendar\Sync_Controller::get_instance();
// Register cron actions
\YachtBooking\Integrations\GoogleCalendar\Sync_Controller::register_cron_actions();
// Load iCal integration
require_once YACHT_BOOKING_PLUGIN_DIR . 'integrations/ical/class-ical-feed.php';
require_once YACHT_BOOKING_PLUGIN_DIR . 'integrations/ical/class-ical-import.php';
\YachtBooking\Integrations\ICal\ICal_Feed::register();
\YachtBooking\Integrations\ICal\ICal_Import::register();
}
/**
* Register Custom Post Types
*/
public function register_post_types() {
// Register Yacht CPT
Yacht::register();
// Register Booking CPT
Booking::register();
// Register Inquiry CPT
Inquiry::register();
}
/**
* Enqueue frontend assets
*/
public function enqueue_frontend_assets() {
// Only load on pages with yacht calendar
if ( ! $this->should_load_frontend_assets() ) {
return;
}
// FullCalendar CSS
wp_enqueue_style(
'fullcalendar',
'https://cdn.jsdelivr.net/npm/fullcalendar@6.1.10/index.global.min.css',
array(),
'6.1.10'
);
// Plugin CSS
wp_enqueue_style(
'yacht-booking-calendar',
YACHT_BOOKING_PLUGIN_URL . 'frontend/assets/css/calendar.css',
array( 'fullcalendar' ),
YACHT_BOOKING_VERSION
);
// FullCalendar JS
wp_enqueue_script(
'fullcalendar',
'https://cdn.jsdelivr.net/npm/fullcalendar@6.1.10/index.global.min.js',
array(),
'6.1.10',
true
);
// FullCalendar Polish locale
wp_enqueue_script(
'fullcalendar-pl',
'https://cdn.jsdelivr.net/npm/@fullcalendar/core@6.1.10/locales/pl.global.min.js',
array( 'fullcalendar' ),
'6.1.10',
true
);
// Plugin JS
wp_enqueue_script(
'yacht-booking-calendar',
YACHT_BOOKING_PLUGIN_URL . 'frontend/assets/js/calendar.js',
array( 'jquery', 'fullcalendar', 'fullcalendar-pl' ),
YACHT_BOOKING_VERSION,
true
);
// Localize script
wp_localize_script(
'yacht-booking-calendar',
'yachtBookingData',
array(
'apiUrl' => esc_url_raw( rest_url( 'yacht-booking/v1' ) ),
'nonce' => wp_create_nonce( 'wp_rest' ),
'bookingEnabled' => Settings::is_booking_enabled(),
'i18n' => array(
'loading' => __( 'Ładowanie...', 'yacht-booking' ),
'submitBooking' => __( 'Wyślij rezerwację', 'yacht-booking' ),
'submitting' => __( 'Wysyłanie...', 'yacht-booking' ),
'successTitle' => __( 'Sukces!', 'yacht-booking' ),
'successMessage' => __( 'Twoja rezerwacja została wysłana. Skontaktujemy się z Tobą wkrótce.', 'yacht-booking' ),
'errorTitle' => __( 'Błąd!', 'yacht-booking' ),
'errorMessage' => __( 'Wystąpił błąd podczas wysyłania rezerwacji. Spróbuj ponownie.', 'yacht-booking' ),
'selectDates' => __( 'Wybierz daty na kalendarzu', 'yacht-booking' ),
'invalidDateRange' => __( 'Nieprawidłowy zakres dat', 'yacht-booking' ),
'unavailableDatesSelected' => __( 'Wybrane daty zawierają niedostępne terminy. Proszę wybrać inne daty.', 'yacht-booking' ),
),
)
);
}
/**
* Enqueue admin assets
*/
public function enqueue_admin_assets( $hook ) {
// Only load on yacht booking pages
if ( strpos( $hook, 'yacht-bookings' ) === false ) {
return;
}
wp_enqueue_style(
'yacht-booking-admin',
YACHT_BOOKING_PLUGIN_URL . 'admin/assets/css/admin.css',
array(),
YACHT_BOOKING_VERSION
);
wp_enqueue_script(
'yacht-booking-admin',
YACHT_BOOKING_PLUGIN_URL . 'admin/assets/js/admin.js',
array( 'jquery' ),
YACHT_BOOKING_VERSION,
true
);
wp_localize_script(
'yacht-booking-admin',
'yachtBookingAdmin',
array(
'apiUrl' => esc_url_raw( rest_url( 'yacht-booking/v1' ) ),
'nonce' => wp_create_nonce( 'wp_rest' ),
)
);
}
/**
* Check if frontend assets should be loaded
*
* @return bool
*/
private function should_load_frontend_assets() {
global $post;
// Always load if Elementor is in edit mode
if ( class_exists( '\Elementor\Plugin' ) && \Elementor\Plugin::$instance->preview->is_preview_mode() ) {
return true;
}
// Check if post contains yacht calendar shortcode or widget
if ( $post && ( has_shortcode( $post->post_content, 'yacht_calendar' ) || $this->has_yacht_calendar_widget( $post->ID ) ) ) {
return true;
}
return false;
}
/**
* Check if post has yacht calendar Elementor widget
*
* @param int $post_id Post ID.
* @return bool
*/
private function has_yacht_calendar_widget( $post_id ) {
if ( ! class_exists( '\Elementor\Plugin' ) ) {
return false;
}
$document = \Elementor\Plugin::$instance->documents->get( $post_id );
if ( ! $document ) {
return false;
}
$data = $document->get_elements_data();
return $this->find_widget_recursive( $data, 'yacht-calendar' );
}
/**
* Find widget recursively in Elementor data
*
* @param array $elements Elements data.
* @param string $widget_name Widget name to find.
* @return bool
*/
private function find_widget_recursive( $elements, $widget_name ) {
foreach ( $elements as $element ) {
if ( isset( $element['widgetType'] ) && $element['widgetType'] === $widget_name ) {
return true;
}
if ( ! empty( $element['elements'] ) ) {
if ( $this->find_widget_recursive( $element['elements'], $widget_name ) ) {
return true;
}
}
}
return false;
}
/**
* Register REST API routes
*/
public function register_rest_routes() {
// Load REST controllers
require_once YACHT_BOOKING_PLUGIN_DIR . 'api/class-rest-controller.php';
$controller = new Rest_Controller();
$controller->register_routes();
}
/**
* Register Elementor widgets
*
* @param object $widgets_manager Elementor widgets manager.
*/
public function register_elementor_widgets( $widgets_manager ) {
// Load widget class
require_once YACHT_BOOKING_PLUGIN_DIR . 'frontend/class-calendar-widget.php';
// Register widget
$widgets_manager->register( new Calendar_Widget() );
}
/**
* Register shortcodes
*/
public function register_shortcodes() {
// Load shortcode class
require_once YACHT_BOOKING_PLUGIN_DIR . 'frontend/class-shortcode.php';
// Initialize shortcode handler
Shortcode::get_instance();
}
/**
* Add custom capabilities
*/
public function add_custom_capabilities() {
// Only run once
if ( get_option( 'yacht_booking_capabilities_added' ) ) {
return;
}
$admin = get_role( 'administrator' );
if ( $admin ) {
$capabilities = array(
'yacht_booking_manage_yachts',
'yacht_booking_manage_bookings',
'yacht_booking_manage_settings',
);
foreach ( $capabilities as $cap ) {
$admin->add_cap( $cap );
}
update_option( 'yacht_booking_capabilities_added', true );
}
}
}

View File

@@ -0,0 +1,155 @@
<?php
/**
* Yacht Custom Post Type
*
* @package YachtBooking
*/
namespace YachtBooking;
// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Yacht CPT class
*/
class Yacht {
/**
* Register custom post type
*/
public static function register() {
$labels = array(
'name' => __( 'Jachty', 'yacht-booking' ),
'singular_name' => __( 'Jacht', 'yacht-booking' ),
'menu_name' => __( 'Jachty', 'yacht-booking' ),
'name_admin_bar' => __( 'Jacht', 'yacht-booking' ),
'add_new' => __( 'Dodaj nowy', 'yacht-booking' ),
'add_new_item' => __( 'Dodaj nowy jacht', 'yacht-booking' ),
'new_item' => __( 'Nowy jacht', 'yacht-booking' ),
'edit_item' => __( 'Edytuj jacht', 'yacht-booking' ),
'view_item' => __( 'Zobacz jacht', 'yacht-booking' ),
'all_items' => __( 'Wszystkie jachty', 'yacht-booking' ),
'search_items' => __( 'Szukaj jachtów', 'yacht-booking' ),
'parent_item_colon' => __( 'Nadrzędny jacht:', 'yacht-booking' ),
'not_found' => __( 'Nie znaleziono jachtów', 'yacht-booking' ),
'not_found_in_trash' => __( 'Nie znaleziono jachtów w koszu', 'yacht-booking' ),
'featured_image' => __( 'Zdjęcie jachtu', 'yacht-booking' ),
'set_featured_image' => __( 'Ustaw zdjęcie jachtu', 'yacht-booking' ),
'remove_featured_image' => __( 'Usuń zdjęcie jachtu', 'yacht-booking' ),
'use_featured_image' => __( 'Użyj jako zdjęcie jachtu', 'yacht-booking' ),
);
$args = array(
'labels' => $labels,
'description' => __( 'Jachty dostępne do rezerwacji', 'yacht-booking' ),
'public' => false,
'publicly_queryable' => false,
'show_ui' => true,
'show_in_menu' => false, // Custom menu będzie w class-admin.php
'show_in_rest' => true,
'query_var' => true,
'rewrite' => false,
'capability_type' => 'post',
'capabilities' => array(
'edit_post' => 'yacht_booking_manage_yachts',
'read_post' => 'yacht_booking_manage_yachts',
'delete_post' => 'yacht_booking_manage_yachts',
'edit_posts' => 'yacht_booking_manage_yachts',
'edit_others_posts' => 'yacht_booking_manage_yachts',
'publish_posts' => 'yacht_booking_manage_yachts',
'read_private_posts' => 'yacht_booking_manage_yachts',
'delete_posts' => 'yacht_booking_manage_yachts',
),
'has_archive' => false,
'hierarchical' => false,
'menu_position' => null,
'supports' => array( 'title', 'editor', 'thumbnail', 'custom-fields' ),
);
register_post_type( 'yacht', $args );
}
/**
* Get yacht capacity
*
* @param int $yacht_id Yacht post ID.
* @return int
*/
public static function get_capacity( $yacht_id ) {
return (int) get_post_meta( $yacht_id, '_yacht_capacity', true );
}
/**
* Get yacht price per day
*
* @param int $yacht_id Yacht post ID.
* @return float
*/
public static function get_price_per_day( $yacht_id ) {
return (float) get_post_meta( $yacht_id, '_yacht_price_per_day', true );
}
/**
* Get yacht Google Calendar ID
*
* @param int $yacht_id Yacht post ID.
* @return string
*/
public static function get_gcal_id( $yacht_id ) {
return get_post_meta( $yacht_id, '_yacht_gcal_id', true );
}
/**
* Get yacht features
*
* @param int $yacht_id Yacht post ID.
* @return array
*/
public static function get_features( $yacht_id ) {
$features = get_post_meta( $yacht_id, '_yacht_features', true );
return is_array( $features ) ? $features : array();
}
/**
* Update yacht capacity
*
* @param int $yacht_id Yacht post ID.
* @param int $capacity Capacity.
*/
public static function update_capacity( $yacht_id, $capacity ) {
update_post_meta( $yacht_id, '_yacht_capacity', (int) $capacity );
}
/**
* Update yacht price per day
*
* @param int $yacht_id Yacht post ID.
* @param float $price Price per day.
*/
public static function update_price_per_day( $yacht_id, $price ) {
update_post_meta( $yacht_id, '_yacht_price_per_day', (float) $price );
}
/**
* Update yacht Google Calendar ID
*
* @param int $yacht_id Yacht post ID.
* @param string $gcal_id Google Calendar ID.
*/
public static function update_gcal_id( $yacht_id, $gcal_id ) {
update_post_meta( $yacht_id, '_yacht_gcal_id', sanitize_text_field( $gcal_id ) );
}
/**
* Update yacht features
*
* @param int $yacht_id Yacht post ID.
* @param array $features Features array.
*/
public static function update_features( $yacht_id, $features ) {
update_post_meta( $yacht_id, '_yacht_features', is_array( $features ) ? $features : array() );
}
}