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,183 @@
/**
* Yacht Booking Admin Styles
*
* @package YachtBooking
*/
/* General Admin Page */
.yacht-bookings-page {
background: #fff;
padding: 20px;
margin-top: 20px;
}
/* Yacht List Table */
.wp-list-table.yachts {
margin-top: 20px;
}
.wp-list-table.yachts th {
font-weight: 600;
}
.wp-list-table.yachts .row-title {
font-weight: 600;
color: #2271b1;
}
.wp-list-table.yachts .row-title:hover {
color: #135e96;
}
/* Google Calendar Status */
.gcal-status {
display: inline-flex;
align-items: center;
gap: 5px;
font-size: 13px;
}
.gcal-status.connected {
color: #28a745;
font-weight: 600;
}
.gcal-status.disconnected {
color: #999;
}
.gcal-status .dashicons {
font-size: 18px;
width: 18px;
height: 18px;
}
/* Yacht Edit Form */
.yacht-edit-form {
max-width: 900px;
}
.yacht-edit-form .form-table th {
width: 200px;
padding: 20px 10px 20px 0;
vertical-align: top;
}
.yacht-edit-form .form-table td {
padding: 15px 10px;
}
.yacht-edit-form .description {
color: #646970;
font-size: 13px;
font-style: normal;
margin-top: 8px;
}
.yacht-edit-form .description a {
text-decoration: none;
}
.yacht-edit-form .description a:hover {
text-decoration: underline;
}
.yacht-edit-form input[type="text"].code {
font-family: Consolas, Monaco, monospace;
font-size: 13px;
}
.yacht-edit-form .gcal-status.connected {
margin-top: 10px;
padding: 8px 12px;
background: #d4edda;
border: 1px solid #c3e6cb;
border-radius: 4px;
display: inline-flex;
}
/* Submit Button */
.yacht-edit-form .submit {
padding: 0;
margin: 20px 0;
}
.yacht-edit-form .button.button-primary.button-large {
height: 36px;
padding: 0 24px;
font-size: 14px;
}
/* Delete Button */
.button-link-delete {
text-decoration: none;
}
.button-link-delete:hover {
color: #a00 !important;
}
/* Booking Status Badges */
.booking-status {
display: inline-block;
padding: 4px 12px;
border-radius: 3px;
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
}
.booking-status.pending {
background: #fef3cd;
color: #856404;
border: 1px solid #ffeeba;
}
.booking-status.confirmed {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.booking-status.cancelled {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
/* Settings Tabs */
.nav-tab-wrapper {
margin-bottom: 20px;
}
/* Form Sections */
.yacht-form-section {
background: #fff;
padding: 20px;
margin-bottom: 20px;
border: 1px solid #ddd;
border-radius: 4px;
}
.yacht-form-section h3 {
margin-top: 0;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
}
/* Notices */
.notice {
margin: 15px 0 20px;
}
/* Responsive */
@media screen and (max-width: 782px) {
.yacht-edit-form .form-table th {
width: auto;
padding: 10px;
}
.yacht-edit-form .form-table td {
padding: 10px;
}
}

View File

@@ -0,0 +1,88 @@
/**
* Yacht Booking Admin JavaScript
*
* @package YachtBooking
*/
;(function($) {
'use strict';
/**
* Admin functionality
*/
const YachtBookingAdmin = {
init: function() {
this.bindEvents();
},
bindEvents: function() {
// Manual sync button
$(document).on('click', '#yacht-booking-manual-sync', this.handleManualSync.bind(this));
},
handleManualSync: function(e) {
e.preventDefault();
const $button = $(e.currentTarget);
const $status = $('#yacht-booking-sync-status');
const $result = $('#yacht-booking-sync-result');
const nonce = $button.data('nonce');
const originalText = $button.text();
// Disable button and show loading
$button.prop('disabled', true).text('Synchronizowanie...');
$status.html('<span class="spinner is-active" style="float: none; margin: 0;"></span>');
$result.empty();
// AJAX call
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'yacht_booking_manual_sync',
nonce: nonce
},
success: function(response) {
if (response.success) {
$result.html(
'<div class="notice notice-success inline"><p>' +
response.data.message +
'</p></div>'
);
} else {
$result.html(
'<div class="notice notice-error inline"><p>' +
response.data.message +
'</p></div>'
);
}
},
error: function(xhr, status, error) {
$result.html(
'<div class="notice notice-error inline"><p>' +
'Błąd połączenia: ' + error +
'</p></div>'
);
},
complete: function() {
// Re-enable button
$button.prop('disabled', false).text(originalText);
$status.empty();
// Auto-hide success message after 5 seconds
setTimeout(function() {
$result.find('.notice-success').fadeOut();
}, 5000);
}
});
}
};
/**
* Document ready
*/
$(document).ready(function() {
YachtBookingAdmin.init();
});
})(jQuery);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,414 @@
<?php
/**
* Booking List Table
*
* @package YachtBooking
*/
namespace YachtBooking;
// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Load WP_List_Table if not loaded
if ( ! class_exists( 'WP_List_Table' ) ) {
require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
}
/**
* Booking List Table class
*/
class Booking_List_Table extends \WP_List_Table {
/**
* Constructor
*/
public function __construct() {
parent::__construct(
array(
'singular' => 'booking',
'plural' => 'bookings',
'ajax' => false,
)
);
}
/**
* Get columns
*
* @return array
*/
public function get_columns() {
return array(
'cb' => '<input type="checkbox" />',
'id' => __( 'ID', 'yacht-booking' ),
'yacht' => __( 'Jacht', 'yacht-booking' ),
'customer' => __( 'Klient', 'yacht-booking' ),
'dates' => __( 'Termin', 'yacht-booking' ),
'status' => __( 'Status', 'yacht-booking' ),
'total_price' => __( 'Cena', 'yacht-booking' ),
'date_created' => __( 'Data utworzenia', 'yacht-booking' ),
);
}
/**
* Get sortable columns
*
* @return array
*/
public function get_sortable_columns() {
return array(
'id' => array( 'ID', true ),
'status' => array( 'status', false ),
'total_price' => array( 'total_price', false ),
'date_created' => array( 'date', true ),
);
}
/**
* Get bulk actions
*
* @return array
*/
public function get_bulk_actions() {
return array(
'approve' => __( 'Zatwierdź', 'yacht-booking' ),
'cancel' => __( 'Anuluj', 'yacht-booking' ),
'delete' => __( 'Usuń', 'yacht-booking' ),
);
}
/**
* Prepare items for display
*/
public function prepare_items() {
$per_page = 20;
$current_page = $this->get_pagenum();
$orderby = isset( $_GET['orderby'] ) ? sanitize_text_field( wp_unslash( $_GET['orderby'] ) ) : 'date';
$order = isset( $_GET['order'] ) ? sanitize_text_field( wp_unslash( $_GET['order'] ) ) : 'DESC';
$search = isset( $_GET['s'] ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : '';
$args = array(
'post_type' => 'yacht_booking',
'posts_per_page' => $per_page,
'paged' => $current_page,
'orderby' => $orderby,
'order' => $order,
'post_status' => 'publish',
);
// Search
if ( ! empty( $search ) ) {
$args['s'] = $search;
}
// Filter by status
if ( ! empty( $_GET['status_filter'] ) && 'all' !== $_GET['status_filter'] ) {
$args['meta_query'] = array(
array(
'key' => '_booking_status',
'value' => sanitize_text_field( wp_unslash( $_GET['status_filter'] ) ),
),
);
}
// Filter by yacht
if ( ! empty( $_GET['yacht_filter'] ) && 'all' !== $_GET['yacht_filter'] ) {
if ( ! isset( $args['meta_query'] ) ) {
$args['meta_query'] = array();
}
$args['meta_query'][] = array(
'key' => '_booking_yacht_id',
'value' => (int) $_GET['yacht_filter'],
);
}
$query = new \WP_Query( $args );
$this->items = $query->posts;
$this->set_pagination_args(
array(
'total_items' => $query->found_posts,
'per_page' => $per_page,
'total_pages' => $query->max_num_pages,
)
);
$columns = $this->get_columns();
$hidden = array();
$sortable = $this->get_sortable_columns();
$this->_column_headers = array( $columns, $hidden, $sortable );
}
/**
* Column checkbox
*
* @param object $item Item.
* @return string
*/
public function column_cb( $item ) {
return sprintf(
'<input type="checkbox" name="booking[]" value="%d" />',
$item->ID
);
}
/**
* Column ID
*
* @param object $item Item.
* @return string
*/
public function column_id( $item ) {
$actions = array();
$status = Booking::get_status( $item->ID );
// Approve action (for pending only)
if ( 'pending' === $status ) {
$approve_url = wp_nonce_url(
admin_url( 'admin.php?page=yacht-bookings-list&action=approve&booking=' . $item->ID ),
'approve_booking_' . $item->ID
);
$actions['approve-booking'] = sprintf(
'<a href="%s" style="color: #28a745;">%s</a>',
esc_url( $approve_url ),
__( 'Zatwierdź', 'yacht-booking' )
);
}
// Cancel action (for pending and confirmed)
if ( in_array( $status, array( 'pending', 'confirmed' ), true ) ) {
$cancel_url = wp_nonce_url(
admin_url( 'admin.php?page=yacht-bookings-list&action=cancel&booking=' . $item->ID ),
'cancel_booking_' . $item->ID
);
$actions['cancel'] = sprintf(
'<a href="%s" style="color: #856404;" onclick="return confirm(\'%s\')">%s</a>',
esc_url( $cancel_url ),
esc_js( __( 'Czy na pewno chcesz anulować tę rezerwację?', 'yacht-booking' ) ),
__( 'Anuluj', 'yacht-booking' )
);
}
// Delete action (always visible)
$delete_url = wp_nonce_url(
admin_url( 'admin.php?page=yacht-bookings-list&action=delete&booking=' . $item->ID ),
'delete_booking_' . $item->ID
);
$actions['delete'] = sprintf(
'<a href="%s" class="submitdelete" onclick="return confirm(\'%s\')">%s</a>',
esc_url( $delete_url ),
esc_js( __( 'Czy na pewno chcesz usunąć tę rezerwację? Tej operacji nie można cofnąć.', 'yacht-booking' ) ),
__( 'Usuń', 'yacht-booking' )
);
return sprintf(
'<strong>#%d</strong>%s',
$item->ID,
$this->row_actions( $actions )
);
}
/**
* Column yacht
*
* @param object $item Item.
* @return string
*/
public function column_yacht( $item ) {
$yacht_id = Booking::get_yacht_id( $item->ID );
$yacht = get_post( $yacht_id );
if ( $yacht ) {
return sprintf(
'<a href="%s">%s</a>',
esc_url( admin_url( 'admin.php?page=yacht-bookings-add-yacht&yacht_id=' . $yacht_id ) ),
esc_html( $yacht->post_title )
);
}
return '—';
}
/**
* Column customer
*
* @param object $item Item.
* @return string
*/
public function column_customer( $item ) {
$customer_name = Booking::get_customer_name( $item->ID );
$customer_email = Booking::get_customer_email( $item->ID );
$customer_phone = Booking::get_customer_phone( $item->ID );
return sprintf(
'<strong>%s</strong><br><small>%s<br>%s</small>',
esc_html( $customer_name ),
esc_html( $customer_email ),
esc_html( $customer_phone )
);
}
/**
* Column dates
*
* @param object $item Item.
* @return string
*/
public function column_dates( $item ) {
$start_date = Booking::get_start_date( $item->ID );
$end_date = Booking::get_end_date( $item->ID );
$days = Availability::count_days( $start_date, $end_date );
return sprintf(
'<strong>%s</strong><br><small>do %s (%d %s)</small>',
esc_html( Settings::format_date( $start_date ) ),
esc_html( Settings::format_date( $end_date ) ),
$days,
_n( 'dzień', 'dni', $days, 'yacht-booking' )
);
}
/**
* Column status
*
* @param object $item Item.
* @return string
*/
public function column_status( $item ) {
$status = Booking::get_status( $item->ID );
$status_labels = array(
'pending' => __( 'Oczekująca', 'yacht-booking' ),
'confirmed' => __( 'Potwierdzona', 'yacht-booking' ),
'cancelled' => __( 'Anulowana', 'yacht-booking' ),
);
$status_label = isset( $status_labels[ $status ] ) ? $status_labels[ $status ] : $status;
return sprintf(
'<span class="booking-status %s">%s</span>',
esc_attr( $status ),
esc_html( $status_label )
);
}
/**
* Column total price
*
* @param object $item Item.
* @return string
*/
public function column_total_price( $item ) {
$total_price = Booking::get_total_price( $item->ID );
if ( $total_price > 0 ) {
return sprintf(
'<strong>%s</strong>',
esc_html( Settings::format_price( $total_price ) )
);
}
return '—';
}
/**
* Column date created
*
* @param object $item Item.
* @return string
*/
public function column_date_created( $item ) {
$date_format = Settings::get_date_format();
return sprintf(
'%s<br><small>%s</small>',
get_the_date( $date_format, $item ),
get_the_time( 'H:i', $item )
);
}
/**
* Default column
*
* @param object $item Item.
* @param string $column_name Column name.
* @return string
*/
public function column_default( $item, $column_name ) {
return '';
}
/**
* Display filters above the table
*/
protected function extra_tablenav( $which ) {
if ( 'top' !== $which ) {
return;
}
$current_status = isset( $_GET['status_filter'] ) ? sanitize_text_field( wp_unslash( $_GET['status_filter'] ) ) : 'all';
$current_yacht = isset( $_GET['yacht_filter'] ) ? (int) $_GET['yacht_filter'] : 'all';
?>
<div class="alignleft actions">
<!-- Status filter -->
<select name="status_filter">
<option value="all" <?php selected( $current_status, 'all' ); ?>>
<?php esc_html_e( 'Wszystkie statusy', 'yacht-booking' ); ?>
</option>
<option value="pending" <?php selected( $current_status, 'pending' ); ?>>
<?php esc_html_e( 'Oczekujące', 'yacht-booking' ); ?>
</option>
<option value="confirmed" <?php selected( $current_status, 'confirmed' ); ?>>
<?php esc_html_e( 'Potwierdzone', 'yacht-booking' ); ?>
</option>
<option value="cancelled" <?php selected( $current_status, 'cancelled' ); ?>>
<?php esc_html_e( 'Anulowane', 'yacht-booking' ); ?>
</option>
</select>
<!-- Yacht filter -->
<select name="yacht_filter">
<option value="all" <?php selected( $current_yacht, 'all' ); ?>>
<?php esc_html_e( 'Wszystkie jachty', 'yacht-booking' ); ?>
</option>
<?php
$yachts = get_posts(
array(
'post_type' => 'yacht',
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC',
)
);
foreach ( $yachts as $yacht ) {
printf(
'<option value="%d" %s>%s</option>',
$yacht->ID,
selected( $current_yacht, $yacht->ID, false ),
esc_html( $yacht->post_title )
);
}
?>
</select>
<input type="submit" class="button" value="<?php esc_attr_e( 'Filtruj', 'yacht-booking' ); ?>">
</div>
<?php
}
/**
* Message when no items
*/
public function no_items() {
esc_html_e( 'Brak rezerwacji.', 'yacht-booking' );
}
}

View File

@@ -0,0 +1,315 @@
<?php
/**
* Inquiry List Table
*
* @package YachtBooking
*/
namespace YachtBooking;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( ! class_exists( 'WP_List_Table' ) ) {
require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
}
/**
* Inquiry List Table class
*/
class Inquiry_List_Table extends \WP_List_Table {
/**
* Constructor
*/
public function __construct() {
parent::__construct(
array(
'singular' => 'inquiry',
'plural' => 'inquiries',
'ajax' => false,
)
);
}
/**
* Get columns
*
* @return array
*/
public function get_columns() {
return array(
'cb' => '<input type="checkbox" />',
'id' => __( 'ID', 'yacht-booking' ),
'yacht' => __( 'Jacht', 'yacht-booking' ),
'customer' => __( 'Klient', 'yacht-booking' ),
'dates' => __( 'Preferowane terminy', 'yacht-booking' ),
'message' => __( 'Wiadomość', 'yacht-booking' ),
'emails' => __( 'Emaile', 'yacht-booking' ),
'date_created' => __( 'Data wysłania', 'yacht-booking' ),
);
}
/**
* Get sortable columns
*
* @return array
*/
public function get_sortable_columns() {
return array(
'id' => array( 'ID', true ),
'date_created' => array( 'date', true ),
);
}
/**
* Get bulk actions
*
* @return array
*/
public function get_bulk_actions() {
return array(
'delete' => __( 'Usu\u0144', 'yacht-booking' ),
);
}
/**
* Prepare items for display
*/
public function prepare_items() {
$per_page = 20;
$current_page = $this->get_pagenum();
$orderby = isset( $_GET['orderby'] ) ? sanitize_text_field( wp_unslash( $_GET['orderby'] ) ) : 'date';
$order = isset( $_GET['order'] ) ? sanitize_text_field( wp_unslash( $_GET['order'] ) ) : 'DESC';
$search = isset( $_GET['s'] ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : '';
$args = array(
'post_type' => 'yacht_inquiry',
'posts_per_page' => $per_page,
'paged' => $current_page,
'orderby' => $orderby,
'order' => $order,
'post_status' => 'publish',
);
if ( ! empty( $search ) ) {
$args['s'] = $search;
}
if ( ! empty( $_GET['yacht_filter'] ) && 'all' !== $_GET['yacht_filter'] ) {
$args['meta_query'] = array(
array(
'key' => '_inquiry_yacht_id',
'value' => (int) $_GET['yacht_filter'],
),
);
}
$query = new \WP_Query( $args );
$this->items = $query->posts;
$this->set_pagination_args(
array(
'total_items' => $query->found_posts,
'per_page' => $per_page,
'total_pages' => $query->max_num_pages,
)
);
$columns = $this->get_columns();
$hidden = array();
$sortable = $this->get_sortable_columns();
$this->_column_headers = array( $columns, $hidden, $sortable );
}
/**
* Column checkbox
*
* @param object $item Item.
* @return string
*/
public function column_cb( $item ) {
return sprintf( '<input type="checkbox" name="inquiry[]" value="%d" />', $item->ID );
}
/**
* Column ID
*
* @param object $item Item.
* @return string
*/
public function column_id( $item ) {
$delete_url = wp_nonce_url(
admin_url( 'admin.php?page=yacht-inquiries&action=delete&inquiry=' . $item->ID ),
'delete_inquiry_' . $item->ID
);
$actions = array(
'delete' => sprintf(
'<a href="%s" class="submitdelete" onclick="return confirm(\'%s\')">%s</a>',
esc_url( $delete_url ),
esc_js( __( 'Czy na pewno chcesz usunac to zapytanie?', 'yacht-booking' ) ),
__( 'Usun', 'yacht-booking' )
),
);
return sprintf( '<strong>#%d</strong>%s', $item->ID, $this->row_actions( $actions ) );
}
/**
* Column yacht
*
* @param object $item Item.
* @return string
*/
public function column_yacht( $item ) {
$yacht_id = Inquiry::get_yacht_id( $item->ID );
$yacht = get_post( $yacht_id );
return $yacht ? esc_html( $yacht->post_title ) : '—';
}
/**
* Column customer
*
* @param object $item Item.
* @return string
*/
public function column_customer( $item ) {
return sprintf(
'<strong>%s</strong><br><small>%s<br>%s</small>',
esc_html( Inquiry::get_customer_name( $item->ID ) ),
esc_html( Inquiry::get_customer_email( $item->ID ) ),
esc_html( Inquiry::get_customer_phone( $item->ID ) )
);
}
/**
* Column preferred dates
*
* @param object $item Item.
* @return string
*/
public function column_dates( $item ) {
$dates = Inquiry::get_preferred_dates( $item->ID );
return $dates ? esc_html( $dates ) : '—';
}
/**
* Column message
*
* @param object $item Item.
* @return string
*/
public function column_message( $item ) {
$message = Inquiry::get_message( $item->ID );
if ( ! $message ) {
return '—';
}
$short = mb_strlen( $message ) > 80 ? mb_substr( $message, 0, 80 ) . '...' : $message;
return '<span title="' . esc_attr( $message ) . '">' . esc_html( $short ) . '</span>';
}
/**
* Column emails — links to view sent emails.
*
* @param object $item Item.
* @return string
*/
public function column_emails( $item ) {
$admin_url = wp_nonce_url(
admin_url( 'admin.php?page=yacht-inquiries&action=view_email&inquiry=' . $item->ID . '&type=admin' ),
'view_email_' . $item->ID
);
$customer_url = wp_nonce_url(
admin_url( 'admin.php?page=yacht-inquiries&action=view_email&inquiry=' . $item->ID . '&type=customer' ),
'view_email_' . $item->ID
);
return sprintf(
'<a href="%s" class="button button-small">%s</a> <a href="%s" class="button button-small">%s</a>',
esc_url( $admin_url ),
esc_html__( 'Do admina', 'yacht-booking' ),
esc_url( $customer_url ),
esc_html__( 'Do klienta', 'yacht-booking' )
);
}
/**
* Column date created
*
* @param object $item Item.
* @return string
*/
public function column_date_created( $item ) {
return sprintf(
'%s<br><small>%s</small>',
get_the_date( Settings::get_date_format(), $item ),
get_the_time( 'H:i', $item )
);
}
/**
* Default column
*
* @param object $item Item.
* @param string $column_name Column name.
* @return string
*/
public function column_default( $item, $column_name ) {
return '';
}
/**
* Filters above table
*
* @param string $which Position.
*/
protected function extra_tablenav( $which ) {
if ( 'top' !== $which ) {
return;
}
$current_yacht = isset( $_GET['yacht_filter'] ) ? (int) $_GET['yacht_filter'] : 'all';
?>
<div class="alignleft actions">
<select name="yacht_filter">
<option value="all" <?php selected( $current_yacht, 'all' ); ?>>
<?php esc_html_e( 'Wszystkie jachty', 'yacht-booking' ); ?>
</option>
<?php
$yachts = get_posts(
array(
'post_type' => 'yacht',
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC',
)
);
foreach ( $yachts as $yacht ) {
printf(
'<option value="%d" %s>%s</option>',
$yacht->ID,
selected( $current_yacht, $yacht->ID, false ),
esc_html( $yacht->post_title )
);
}
?>
</select>
<input type="submit" class="button" value="<?php esc_attr_e( 'Filtruj', 'yacht-booking' ); ?>">
</div>
<?php
}
/**
* No items message
*/
public function no_items() {
esc_html_e( 'Brak zapytań.', 'yacht-booking' );
}
}

View File

@@ -0,0 +1,259 @@
<?php
/**
* Yacht List Table
*
* @package YachtBooking
*/
namespace YachtBooking;
// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Load WP_List_Table if not loaded
if ( ! class_exists( 'WP_List_Table' ) ) {
require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
}
/**
* Yacht List Table class
*/
class Yacht_List_Table extends \WP_List_Table {
/**
* Constructor
*/
public function __construct() {
parent::__construct(
array(
'singular' => 'yacht',
'plural' => 'yachts',
'ajax' => false,
)
);
}
/**
* Get columns
*
* @return array
*/
public function get_columns() {
return array(
'cb' => '<input type="checkbox" />',
'title' => __( 'Nazwa jachtu', 'yacht-booking' ),
'gcal' => __( 'Google Calendar', 'yacht-booking' ),
'bookings' => __( 'Rezerwacje', 'yacht-booking' ),
'date' => __( 'Data utworzenia', 'yacht-booking' ),
);
}
/**
* Get sortable columns
*
* @return array
*/
public function get_sortable_columns() {
return array(
'title' => array( 'title', false ),
'date' => array( 'date', true ),
);
}
/**
* Get bulk actions
*
* @return array
*/
public function get_bulk_actions() {
return array(
'delete' => __( 'Usuń', 'yacht-booking' ),
);
}
/**
* Prepare items for display
*/
public function prepare_items() {
$per_page = 20;
$current_page = $this->get_pagenum();
$orderby = isset( $_GET['orderby'] ) ? sanitize_text_field( wp_unslash( $_GET['orderby'] ) ) : 'title';
$order = isset( $_GET['order'] ) ? sanitize_text_field( wp_unslash( $_GET['order'] ) ) : 'ASC';
$search = isset( $_GET['s'] ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : '';
$args = array(
'post_type' => 'yacht',
'posts_per_page' => $per_page,
'paged' => $current_page,
'orderby' => $orderby,
'order' => $order,
'post_status' => 'publish',
);
if ( ! empty( $search ) ) {
$args['s'] = $search;
}
$query = new \WP_Query( $args );
$this->items = $query->posts;
$this->set_pagination_args(
array(
'total_items' => $query->found_posts,
'per_page' => $per_page,
'total_pages' => $query->max_num_pages,
)
);
$columns = $this->get_columns();
$hidden = array();
$sortable = $this->get_sortable_columns();
$this->_column_headers = array( $columns, $hidden, $sortable );
}
/**
* Column checkbox
*
* @param object $item Item.
* @return string
*/
public function column_cb( $item ) {
return sprintf(
'<input type="checkbox" name="yacht[]" value="%d" />',
$item->ID
);
}
/**
* Column title
*
* @param object $item Item.
* @return string
*/
public function column_title( $item ) {
$edit_url = admin_url( 'admin.php?page=yacht-bookings-add-yacht&yacht_id=' . $item->ID );
$delete_url = wp_nonce_url(
admin_url( 'admin.php?page=yacht-bookings&action=delete&yacht=' . $item->ID ),
'delete_yacht_' . $item->ID
);
$actions = array(
'edit' => sprintf(
'<a href="%s">%s</a>',
esc_url( $edit_url ),
__( 'Edytuj', 'yacht-booking' )
),
'delete' => sprintf(
'<a href="%s" class="submitdelete" onclick="return confirm(\'%s\')">%s</a>',
esc_url( $delete_url ),
esc_js( __( 'Czy na pewno chcesz usunąć ten jacht? Spowoduje to również usunięcie wszystkich powiązanych rezerwacji.', 'yacht-booking' ) ),
__( 'Usuń', 'yacht-booking' )
),
);
return sprintf(
'<strong><a href="%s" class="row-title">%s</a></strong>%s',
esc_url( $edit_url ),
esc_html( $item->post_title ),
$this->row_actions( $actions )
);
}
/**
* Column Google Calendar
*
* @param object $item Item.
* @return string
*/
public function column_gcal( $item ) {
$gcal_id = Yacht::get_gcal_id( $item->ID );
if ( $gcal_id ) {
return sprintf(
'<span class="gcal-status connected"><span class="dashicons dashicons-yes-alt"></span> %s</span>',
esc_html__( 'Połączony', 'yacht-booking' )
);
}
return sprintf(
'<span class="gcal-status disconnected"><span class="dashicons dashicons-dismiss"></span> %s</span>',
esc_html__( 'Niepołączony', 'yacht-booking' )
);
}
/**
* Column bookings count
*
* @param object $item Item.
* @return string
*/
public function column_bookings( $item ) {
$count = $this->count_bookings( $item->ID );
if ( $count > 0 ) {
return sprintf(
'<a href="%s">%d</a>',
esc_url( admin_url( 'admin.php?page=yacht-bookings-list&yacht_filter=' . $item->ID ) ),
$count
);
}
return '0';
}
/**
* Column date
*
* @param object $item Item.
* @return string
*/
public function column_date( $item ) {
return get_the_date( Settings::get_date_format() . ' H:i', $item );
}
/**
* Default column
*
* @param object $item Item.
* @param string $column_name Column name.
* @return string
*/
public function column_default( $item, $column_name ) {
return '';
}
/**
* Count bookings for yacht
*
* @param int $yacht_id Yacht ID.
* @return int
*/
private function count_bookings( $yacht_id ) {
$query = new \WP_Query(
array(
'post_type' => 'yacht_booking',
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => '_booking_yacht_id',
'value' => $yacht_id,
),
),
'fields' => 'ids',
)
);
return $query->found_posts;
}
/**
* Message when no items
*/
public function no_items() {
esc_html_e( 'Brak jachtów. Dodaj pierwszy jacht!', 'yacht-booking' );
}
}

View File

@@ -0,0 +1,243 @@
<?php
/**
* Yacht Edit Form View
*
* @package YachtBooking
*/
// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Get yacht data
$title = $yacht ? $yacht->post_title : '';
$content = $yacht ? $yacht->post_content : '';
$gcal_id = $yacht ? \YachtBooking\Yacht::get_gcal_id( $yacht->ID ) : '';
$ical_import_url = $yacht ? \YachtBooking\Integrations\ICal\ICal_Import::get_import_url( $yacht->ID ) : '';
$ical_feed_url = $yacht ? \YachtBooking\Integrations\ICal\ICal_Feed::get_feed_url( $yacht->ID ) : '';
$ical_last_import = $yacht ? \YachtBooking\Integrations\ICal\ICal_Import::get_last_import_time( $yacht->ID ) : '';
$page_title = $yacht ? __( 'Edytuj Jacht', 'yacht-booking' ) : __( 'Dodaj Jacht', 'yacht-booking' );
?>
<div class="wrap">
<h1><?php echo esc_html( $page_title ); ?></h1>
<?php
// Success message
if ( isset( $_GET['saved'] ) ) {
echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__( 'Jacht został zapisany.', 'yacht-booking' ) . '</p></div>';
}
?>
<form method="post" action="" class="yacht-edit-form">
<?php wp_nonce_field( 'yacht_booking_save_yacht', 'yacht_booking_nonce' ); ?>
<input type="hidden" name="yacht_booking_save_yacht" value="1" />
<table class="form-table" role="presentation">
<tbody>
<!-- Nazwa jachtu -->
<tr>
<th scope="row">
<label for="yacht_title">
<?php esc_html_e( 'Nazwa jachtu', 'yacht-booking' ); ?>
<span class="description"> (<?php esc_html_e( 'wymagane', 'yacht-booking' ); ?>)</span>
</label>
</th>
<td>
<input
type="text"
name="yacht_title"
id="yacht_title"
value="<?php echo esc_attr( $title ); ?>"
class="regular-text"
required
/>
<p class="description">
<?php esc_html_e( 'Podaj nazwę jachtu, np. "Laguna 42" lub "Bavaria Cruiser 46"', 'yacht-booking' ); ?>
</p>
</td>
</tr>
<!-- Opis jachtu -->
<tr>
<th scope="row">
<label for="yacht_description">
<?php esc_html_e( 'Opis jachtu', 'yacht-booking' ); ?>
</label>
</th>
<td>
<?php
wp_editor(
$content,
'yacht_description',
array(
'textarea_name' => 'yacht_description',
'textarea_rows' => 10,
'media_buttons' => true,
'teeny' => false,
'tinymce' => array(
'toolbar1' => 'formatselect,bold,italic,underline,bullist,numlist,link,unlink,blockquote,alignleft,aligncenter,alignright',
),
)
);
?>
<p class="description">
<?php esc_html_e( 'Szczegółowy opis jachtu: parametry techniczne, wyposażenie, udogodnienia itp.', 'yacht-booking' ); ?>
</p>
</td>
</tr>
<!-- Google Calendar ID -->
<tr>
<th scope="row">
<label for="yacht_gcal_id">
<?php esc_html_e( 'Google Calendar ID', 'yacht-booking' ); ?>
</label>
</th>
<td>
<input
type="text"
name="yacht_gcal_id"
id="yacht_gcal_id"
value="<?php echo esc_attr( $gcal_id ); ?>"
class="regular-text code"
placeholder="nazwa@group.calendar.google.com"
/>
<p class="description">
<?php
echo wp_kses_post(
sprintf(
/* translators: %s: link to Google Calendar settings */
__( 'ID kalendarza Google do synchronizacji rezerwacji. <a href="%s" target="_blank">Jak znaleźć Calendar ID?</a>', 'yacht-booking' ),
'https://docs.simplecalendar.io/find-google-calendar-id/'
)
);
?>
</p>
<?php if ( $gcal_id ) : ?>
<p class="gcal-status connected">
<span class="dashicons dashicons-yes-alt"></span>
<?php esc_html_e( 'Połączony z Google Calendar', 'yacht-booking' ); ?>
</p>
<?php endif; ?>
</td>
</tr>
<!-- iCal Import URL -->
<tr>
<th scope="row">
<label for="yacht_ical_import_url">
<?php esc_html_e( 'Import iCal (URL)', 'yacht-booking' ); ?>
</label>
</th>
<td>
<input
type="url"
name="yacht_ical_import_url"
id="yacht_ical_import_url"
value="<?php echo esc_attr( $ical_import_url ); ?>"
class="large-text code"
placeholder="https://calendar.google.com/calendar/ical/...basic.ics"
/>
<p class="description">
<?php esc_html_e( 'Wklej adres URL pliku .ics z Google Calendar (lub innego kalendarza). Wydarzenia zostaną zaimportowane jako zablokowane terminy (synchronizacja co godzinę).', 'yacht-booking' ); ?>
</p>
<p class="description">
<strong><?php esc_html_e( 'Jak uzyskać link iCal z Google Calendar:', 'yacht-booking' ); ?></strong>
<?php esc_html_e( 'Google Calendar → Ustawienia → Wybierz kalendarz → „Tajny adres w formacie iCal" → Skopiuj link.', 'yacht-booking' ); ?>
</p>
<?php if ( $ical_last_import ) : ?>
<p>
<span class="dashicons dashicons-update" style="color: #2271b1;"></span>
<?php
printf(
/* translators: %s: date/time */
esc_html__( 'Ostatni import: %s', 'yacht-booking' ),
esc_html( $ical_last_import )
);
?>
</p>
<?php endif; ?>
</td>
</tr>
<?php if ( $yacht ) : ?>
<!-- iCal Export Feed URL -->
<tr>
<th scope="row">
<?php esc_html_e( 'Eksport iCal (feed)', 'yacht-booking' ); ?>
</th>
<td>
<input
type="text"
value="<?php echo esc_attr( $ical_feed_url ); ?>"
class="large-text code"
readonly
onclick="this.select();"
/>
<p class="description">
<?php esc_html_e( 'Skopiuj ten link i dodaj go w Google Calendar (Inne kalendarze → Z adresu URL), aby rezerwacje z tego systemu pojawiły się w Twoim kalendarzu.', 'yacht-booking' ); ?>
</p>
</td>
</tr>
<?php endif; ?>
</tbody>
</table>
<?php submit_button( __( 'Zapisz jacht', 'yacht-booking' ), 'primary large', 'submit', true ); ?>
<?php if ( $yacht ) : ?>
<p>
<a href="<?php echo esc_url( admin_url( 'admin.php?page=yacht-bookings' ) ); ?>" class="button button-secondary">
<?php esc_html_e( 'Anuluj', 'yacht-booking' ); ?>
</a>
<a
href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?page=yacht-bookings&action=delete&yacht=' . $yacht->ID ), 'delete_yacht_' . $yacht->ID ) ); ?>"
class="button button-link-delete"
onclick="return confirm('<?php echo esc_js( __( 'Czy na pewno chcesz usunąć ten jacht? Spowoduje to również usunięcie wszystkich powiązanych rezerwacji.', 'yacht-booking' ) ); ?>');"
style="color: #b32d2e; margin-left: 10px;"
>
<?php esc_html_e( 'Usuń jacht', 'yacht-booking' ); ?>
</a>
</p>
<?php endif; ?>
</form>
<?php if ( $yacht ) : ?>
<!-- Informacje o rezerwacjach -->
<hr />
<h2><?php esc_html_e( 'Powiązane rezerwacje', 'yacht-booking' ); ?></h2>
<?php
$bookings = get_posts(
array(
'post_type' => 'yacht_booking',
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => '_booking_yacht_id',
'value' => $yacht->ID,
),
),
)
);
if ( $bookings ) :
?>
<p>
<?php
printf(
esc_html( _n( 'Ten jacht ma %d rezerwację.', 'Ten jacht ma %d rezerwacji.', count( $bookings ), 'yacht-booking' ) ),
count( $bookings )
);
?>
<a href="<?php echo esc_url( admin_url( 'admin.php?page=yacht-bookings-list&yacht_id=' . $yacht->ID ) ); ?>">
<?php esc_html_e( 'Zobacz rezerwacje', 'yacht-booking' ); ?>
</a>
</p>
<?php else : ?>
<p><?php esc_html_e( 'Brak rezerwacji dla tego jachtu.', 'yacht-booking' ); ?></p>
<?php endif; ?>
<?php endif; ?>
</div>