array( 'label' => 'Nowe', 'color' => '#2F2482' ), 'przeczytane' => array( 'label' => 'Przeczytane', 'color' => '#f59e0b' ), 'zrealizowane' => array( 'label' => 'Zrealizowane', 'color' => '#22c55e' ), ); public function __construct() { add_action( 'init', array( $this, 'register_post_type' ) ); add_filter( 'manage_' . self::POST_TYPE . '_posts_columns', array( $this, 'admin_columns' ) ); add_action( 'manage_' . self::POST_TYPE . '_posts_custom_column', array( $this, 'render_column' ), 10, 2 ); add_action( 'restrict_manage_posts', array( $this, 'status_filter_dropdown' ) ); add_action( 'pre_get_posts', array( $this, 'filter_by_status' ) ); add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ) ); add_action( 'save_post_' . self::POST_TYPE, array( $this, 'save_meta_box' ), 10, 2 ); add_action( 'edit_form_after_title', array( $this, 'auto_mark_read' ) ); add_action( 'admin_head', array( $this, 'admin_styles' ) ); add_action( 'admin_menu', array( $this, 'register_protection_packages_page' ) ); add_action( 'admin_post_carei_save_protection_packages', array( $this, 'handle_protection_packages_save' ) ); } // ─── Protection Packages (SOFT / PREMIUM) ──────────────────── public static function get_protection_packages_defaults() { return array( 'soft' => array( 'name' => 'Ubezpieczenie SOFT', 'pricePerDay' => 0, 'active' => true, 'description' => '', ), 'premium' => array( 'name' => 'Ubezpieczenie PREMIUM', 'pricePerDay' => 0, 'active' => true, 'description' => '', ), ); } public static function get_protection_packages() { $defaults = self::get_protection_packages_defaults(); $stored = get_option( self::PROTECTION_OPTION, array() ); if ( ! is_array( $stored ) ) { $stored = array(); } $out = array(); foreach ( $defaults as $key => $def ) { $item = isset( $stored[ $key ] ) && is_array( $stored[ $key ] ) ? $stored[ $key ] : array(); $out[ $key ] = array( 'name' => isset( $item['name'] ) && $item['name'] !== '' ? (string) $item['name'] : $def['name'], 'pricePerDay' => isset( $item['pricePerDay'] ) ? (float) $item['pricePerDay'] : (float) $def['pricePerDay'], 'active' => isset( $item['active'] ) ? (bool) $item['active'] : (bool) $def['active'], 'description' => isset( $item['description'] ) ? (string) $item['description'] : $def['description'], ); } return $out; } public function register_protection_packages_page() { add_submenu_page( 'edit.php?post_type=' . self::POST_TYPE, 'Pakiety ochronne', 'Pakiety ochronne', 'manage_options', 'carei-protection-packages', array( $this, 'render_protection_packages_page' ) ); } public function render_protection_packages_page() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( 'Brak uprawnień.' ); } $data = self::get_protection_packages(); $saved = isset( $_GET['carei_saved'] ) && $_GET['carei_saved'] === '1'; ?>

Pakiety ochronne

Konfiguracja pakietów wyświetlanych w sekcji Pakiety ochronne formularza rezerwacji. Cena podawana jest za dobę — total = cena × liczba dób rezerwacji.

Zapisano.

'SOFT', 'premium' => 'PREMIUM' ) as $key => $label ) : $pkg = $data[ $key ]; ?>

Pakiet

Status
$def ) { $raw = isset( $input[ $key ] ) && is_array( $input[ $key ] ) ? $input[ $key ] : array(); $name = isset( $raw['name'] ) ? sanitize_text_field( wp_unslash( $raw['name'] ) ) : $def['name']; $price = isset( $raw['pricePerDay'] ) ? (float) $raw['pricePerDay'] : 0; if ( $price < 0 ) { $price = 0; } $active = ! empty( $raw['active'] ); $desc = isset( $raw['description'] ) ? sanitize_textarea_field( wp_unslash( $raw['description'] ) ) : ''; $clean[ $key ] = array( 'name' => $name !== '' ? $name : $def['name'], 'pricePerDay' => $price, 'active' => $active, 'description' => $desc, ); } update_option( self::PROTECTION_OPTION, $clean ); $redirect = add_query_arg( array( 'post_type' => self::POST_TYPE, 'page' => 'carei-protection-packages', 'carei_saved' => '1', ), admin_url( 'edit.php' ) ); wp_safe_redirect( $redirect ); exit; } public function register_post_type() { register_post_type( self::POST_TYPE, array( 'labels' => array( 'name' => 'Rezerwacje', 'singular_name' => 'Rezerwacja', 'menu_name' => 'Rezerwacje', 'all_items' => 'Wszystkie rezerwacje', 'view_item' => 'Zobacz rezerwację', 'edit_item' => 'Szczegóły rezerwacji', 'search_items' => 'Szukaj rezerwacji', 'not_found' => 'Nie znaleziono rezerwacji', 'not_found_in_trash' => 'Brak rezerwacji w koszu', ), 'public' => false, 'show_ui' => true, 'show_in_menu' => true, 'menu_icon' => 'dashicons-car', 'menu_position' => 26, 'supports' => array( 'title' ), 'capability_type' => 'post', 'has_archive' => false, 'hierarchical' => false, 'show_in_rest' => false, ) ); } // ─── Admin Columns ────────────────────────────────────────── public function admin_columns( $columns ) { return array( 'cb' => '', 'reservation_no' => 'Nr rezerwacji', 'client' => 'Klient', 'segment' => 'Segment', 'dates' => 'Daty', 'branch' => 'Oddział', 'carei_status' => 'Status', 'date' => 'Data', ); } public function render_column( $column, $post_id ) { switch ( $column ) { case 'reservation_no': $no = get_post_meta( $post_id, self::META_PREFIX . 'reservation_no', true ) ?: '—'; printf( '%s', esc_url( get_edit_post_link( $post_id ) ), esc_html( $no ) ); break; case 'client': $first = get_post_meta( $post_id, self::META_PREFIX . 'first_name', true ); $last = get_post_meta( $post_id, self::META_PREFIX . 'last_name', true ); echo esc_html( trim( $first . ' ' . $last ) ?: '—' ); break; case 'segment': echo esc_html( get_post_meta( $post_id, self::META_PREFIX . 'segment', true ) ?: '—' ); break; case 'dates': $from = get_post_meta( $post_id, self::META_PREFIX . 'date_from', true ); $to = get_post_meta( $post_id, self::META_PREFIX . 'date_to', true ); if ( $from && $to ) { $from_fmt = date_i18n( 'd.m.Y H:i', strtotime( $from ) ); $to_fmt = date_i18n( 'd.m.Y H:i', strtotime( $to ) ); echo esc_html( $from_fmt . ' — ' . $to_fmt ); } else { echo '—'; } break; case 'branch': echo esc_html( get_post_meta( $post_id, self::META_PREFIX . 'pickup_branch', true ) ?: '—' ); break; case 'carei_status': $status = get_post_meta( $post_id, self::META_PREFIX . 'status', true ) ?: 'nowe'; $info = isset( self::$statuses[ $status ] ) ? self::$statuses[ $status ] : self::$statuses['nowe']; printf( '%s', esc_attr( $info['color'] ), esc_html( $info['label'] ) ); break; } } // ─── Status Filter ────────────────────────────────────────── public function status_filter_dropdown( $post_type ) { if ( $post_type !== self::POST_TYPE ) { return; } $current = isset( $_GET['carei_status'] ) ? sanitize_text_field( $_GET['carei_status'] ) : ''; echo ''; } public function filter_by_status( $query ) { if ( ! is_admin() || ! $query->is_main_query() ) { return; } if ( ( $query->get( 'post_type' ) !== self::POST_TYPE ) ) { return; } if ( ! empty( $_GET['carei_status'] ) ) { $status = sanitize_text_field( $_GET['carei_status'] ); if ( isset( self::$statuses[ $status ] ) ) { $query->set( 'meta_query', array( array( 'key' => self::META_PREFIX . 'status', 'value' => $status, ), ) ); } } // Default sort by date desc if ( ! $query->get( 'orderby' ) ) { $query->set( 'orderby', 'date' ); $query->set( 'order', 'DESC' ); } } // ─── Meta Box ─────────────────────────────────────────────── public function add_meta_boxes() { add_meta_box( 'carei_reservation_details', 'Szczegóły rezerwacji', array( $this, 'render_meta_box' ), self::POST_TYPE, 'normal', 'high' ); } public function render_meta_box( $post ) { wp_nonce_field( 'carei_save_reservation', 'carei_reservation_nonce' ); $meta = array( 'reservation_no' => get_post_meta( $post->ID, self::META_PREFIX . 'reservation_no', true ), 'reservation_id' => get_post_meta( $post->ID, self::META_PREFIX . 'reservation_id', true ), 'customer_id' => get_post_meta( $post->ID, self::META_PREFIX . 'customer_id', true ), 'segment' => get_post_meta( $post->ID, self::META_PREFIX . 'segment', true ), 'date_from' => get_post_meta( $post->ID, self::META_PREFIX . 'date_from', true ), 'date_to' => get_post_meta( $post->ID, self::META_PREFIX . 'date_to', true ), 'pickup_branch' => get_post_meta( $post->ID, self::META_PREFIX . 'pickup_branch', true ), 'return_branch' => get_post_meta( $post->ID, self::META_PREFIX . 'return_branch', true ), 'first_name' => get_post_meta( $post->ID, self::META_PREFIX . 'first_name', true ), 'last_name' => get_post_meta( $post->ID, self::META_PREFIX . 'last_name', true ), 'email' => get_post_meta( $post->ID, self::META_PREFIX . 'email', true ), 'phone' => get_post_meta( $post->ID, self::META_PREFIX . 'phone', true ), 'pesel' => get_post_meta( $post->ID, self::META_PREFIX . 'pesel', true ), 'address' => get_post_meta( $post->ID, self::META_PREFIX . 'address', true ), 'extras' => get_post_meta( $post->ID, self::META_PREFIX . 'extras', true ), 'comments' => get_post_meta( $post->ID, self::META_PREFIX . 'comments', true ), 'status' => get_post_meta( $post->ID, self::META_PREFIX . 'status', true ) ?: 'nowe', 'protection' => get_post_meta( $post->ID, self::META_PREFIX . 'protection_package', true ), ); $protection = $meta['protection'] ? json_decode( $meta['protection'], true ) : null; $protection_str = ''; if ( is_array( $protection ) && ! empty( $protection['name'] ) ) { $name = isset( $protection['name'] ) ? $protection['name'] : ''; $price = isset( $protection['pricePerDay'] ) ? (float) $protection['pricePerDay'] : 0; $days = isset( $protection['days'] ) ? (int) $protection['days'] : 0; $total = isset( $protection['total'] ) ? (float) $protection['total'] : ( $price * $days ); $protection_str = sprintf( '%s — %s zł/doba × %d = %s zł', $name, number_format( $price, 2, ',', ' ' ), $days, number_format( $total, 2, ',', ' ' ) ); } $address = $meta['address'] ? json_decode( $meta['address'], true ) : null; $address_str = ''; if ( $address ) { $parts = array_filter( array( isset( $address['street'] ) ? $address['street'] : '', isset( $address['zipCode'] ) ? $address['zipCode'] : '', isset( $address['city'] ) ? $address['city'] : '', ) ); $address_str = implode( ', ', $parts ); } $extras = $meta['extras'] ? json_decode( $meta['extras'], true ) : array(); $extras_str = ''; if ( is_array( $extras ) && ! empty( $extras ) ) { $names = array_map( function ( $e ) { return isset( $e['name'] ) ? $e['name'] : ''; }, $extras ); $extras_str = implode( ', ', array_filter( $names ) ); } $from_fmt = $meta['date_from'] ? date_i18n( 'd.m.Y H:i', strtotime( $meta['date_from'] ) ) : '—'; $to_fmt = $meta['date_to'] ? date_i18n( 'd.m.Y H:i', strtotime( $meta['date_to'] ) ) : '—'; ?>
Nr rezerwacji
ID rezerwacji (Softra)
ID klienta (Softra)

Segment
Data od
Data do
Oddział odbioru
Oddział zwrotu

Imię
Nazwisko
Email
Telefon
PESEL
Adres

Opcje dodatkowe
Pakiet ochronny
Wiadomość

Status
post_type !== self::POST_TYPE ) { return; } $status = get_post_meta( $post->ID, self::META_PREFIX . 'status', true ); if ( $status === 'nowe' ) { update_post_meta( $post->ID, self::META_PREFIX . 'status', 'przeczytane' ); } } // ─── Admin Styles ─────────────────────────────────────────── public function admin_styles() { $screen = get_current_screen(); if ( ! $screen || $screen->post_type !== self::POST_TYPE ) { return; } ?> self::POST_TYPE, 'post_title' => trim( $title ), 'post_status' => 'publish', ), true ); if ( is_wp_error( $post_id ) ) { error_log( 'Carei: Failed to save reservation — ' . $post_id->get_error_message() ); return false; } $pickup_branch = ''; if ( isset( $booking_data['pickUpLocation']['branchName'] ) ) { $pickup_branch = $booking_data['pickUpLocation']['branchName']; } $return_branch = ''; if ( isset( $booking_data['returnLocation']['branchName'] ) ) { $return_branch = $booking_data['returnLocation']['branchName']; } $segment = ''; if ( isset( $booking_data['carParameters']['categoryName'] ) ) { $segment = $booking_data['carParameters']['categoryName']; } $meta = array( 'reservation_no' => $reservation_no, 'reservation_id' => $reservation_id, 'customer_id' => isset( $booking_data['customerId'] ) ? $booking_data['customerId'] : '', 'segment' => $segment, 'date_from' => isset( $booking_data['dateFrom'] ) ? $booking_data['dateFrom'] : '', 'date_to' => isset( $booking_data['dateTo'] ) ? $booking_data['dateTo'] : '', 'pickup_branch' => $pickup_branch, 'return_branch' => $return_branch, 'first_name' => $first_name, 'last_name' => $last_name, 'email' => isset( $driver['email'] ) ? $driver['email'] : '', 'phone' => isset( $driver['phone'] ) ? $driver['phone'] : '', 'pesel' => isset( $driver['pesel'] ) ? $driver['pesel'] : '', 'address' => isset( $driver['address'] ) ? wp_json_encode( $driver['address'] ) : '', 'extras' => isset( $booking_data['priceItems'] ) ? wp_json_encode( $booking_data['priceItems'] ) : '', 'comments' => isset( $booking_data['comments'] ) ? $booking_data['comments'] : '', 'status' => 'nowe', 'raw_response' => wp_json_encode( $api_result ), 'protection_package' => ( isset( $booking_data['protectionPackage'] ) && is_array( $booking_data['protectionPackage'] ) ) ? wp_json_encode( $booking_data['protectionPackage'] ) : '', ); foreach ( $meta as $key => $value ) { update_post_meta( $post_id, self::META_PREFIX . $key, $value ); } return $post_id; } }