update
This commit is contained in:
@@ -32,18 +32,18 @@ class ICal_Feed {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add rewrite rule for ical feed
|
||||
* Add rewrite rule for global ical feed
|
||||
*/
|
||||
public static function add_rewrite_rules() {
|
||||
add_rewrite_rule(
|
||||
'^yacht-ical/([0-9]+)/([a-zA-Z0-9]+)\.ics$',
|
||||
'index.php?yacht_ical_id=$matches[1]&yacht_ical_token=$matches[2]',
|
||||
'^yacht-ical-global/([a-zA-Z0-9]+)\.ics$',
|
||||
'index.php?yacht_ical_global=1&yacht_ical_token=$matches[1]',
|
||||
'top'
|
||||
);
|
||||
|
||||
// Flush rewrite rules if our rule is not registered yet.
|
||||
$rules = get_option( 'rewrite_rules' );
|
||||
if ( is_array( $rules ) && ! isset( $rules['^yacht-ical/([0-9]+)/([a-zA-Z0-9]+)\.ics$'] ) ) {
|
||||
if ( is_array( $rules ) && ! isset( $rules['^yacht-ical-global/([a-zA-Z0-9]+)\.ics$'] ) ) {
|
||||
flush_rewrite_rules( false );
|
||||
}
|
||||
}
|
||||
@@ -55,94 +55,82 @@ class ICal_Feed {
|
||||
* @return array
|
||||
*/
|
||||
public static function add_query_vars( $vars ) {
|
||||
$vars[] = 'yacht_ical_id';
|
||||
$vars[] = 'yacht_ical_token';
|
||||
$vars[] = 'yacht_ical_global';
|
||||
return $vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle feed request
|
||||
* Handle feed request — globalny feed iCal (jeden plik dla całej floty).
|
||||
*/
|
||||
public static function handle_feed_request() {
|
||||
$yacht_id = (int) get_query_var( 'yacht_ical_id', 0 );
|
||||
$token = get_query_var( 'yacht_ical_token', '' );
|
||||
$is_global = (int) get_query_var( 'yacht_ical_global', 0 );
|
||||
$token = get_query_var( 'yacht_ical_token', '' );
|
||||
|
||||
if ( ! $yacht_id || ! $token ) {
|
||||
if ( ! $is_global || ! $token ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$yacht = get_post( $yacht_id );
|
||||
if ( ! $yacht || 'yacht' !== $yacht->post_type ) {
|
||||
status_header( 404 );
|
||||
exit;
|
||||
}
|
||||
|
||||
$stored_token = self::get_feed_token( $yacht_id );
|
||||
$stored_token = self::get_global_feed_token();
|
||||
if ( ! $stored_token || ! hash_equals( $stored_token, $token ) ) {
|
||||
status_header( 403 );
|
||||
exit;
|
||||
}
|
||||
|
||||
self::output_ics( $yacht );
|
||||
self::output_global_ics();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create feed token for a yacht
|
||||
* Get or create global feed token (one shared token for all-yachts feed).
|
||||
*
|
||||
* @param int $yacht_id Yacht ID.
|
||||
* @return string
|
||||
*/
|
||||
public static function get_feed_token( $yacht_id ) {
|
||||
$token = get_post_meta( $yacht_id, '_yacht_ical_token', true );
|
||||
public static function get_global_feed_token() {
|
||||
$token = get_option( 'yacht_booking_global_ical_token', '' );
|
||||
|
||||
if ( empty( $token ) ) {
|
||||
$token = wp_generate_password( 24, false );
|
||||
update_post_meta( $yacht_id, '_yacht_ical_token', $token );
|
||||
update_option( 'yacht_booking_global_ical_token', $token );
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerate feed token
|
||||
* Regenerate global feed token (invalidates the previous URL).
|
||||
*
|
||||
* @param int $yacht_id Yacht ID.
|
||||
* @return string
|
||||
*/
|
||||
public static function regenerate_token( $yacht_id ) {
|
||||
public static function regenerate_global_token() {
|
||||
$token = wp_generate_password( 24, false );
|
||||
update_post_meta( $yacht_id, '_yacht_ical_token', $token );
|
||||
update_option( 'yacht_booking_global_ical_token', $token );
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get feed URL for a yacht
|
||||
* Get global feed URL (all yachts in one .ics).
|
||||
*
|
||||
* @param int $yacht_id Yacht ID.
|
||||
* @return string
|
||||
*/
|
||||
public static function get_feed_url( $yacht_id ) {
|
||||
$token = self::get_feed_token( $yacht_id );
|
||||
return home_url( sprintf( '/yacht-ical/%d/%s.ics', $yacht_id, $token ) );
|
||||
public static function get_global_feed_url() {
|
||||
$token = self::get_global_feed_token();
|
||||
return home_url( sprintf( '/yacht-ical-global/%s.ics', $token ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Output .ics file
|
||||
* Output global .ics feed — wszystkie jachty w jednym pliku.
|
||||
*
|
||||
* @param \WP_Post $yacht Yacht post.
|
||||
* Każdy event ma SUMMARY w formacie "{nazwa_jachtu} - {klient}".
|
||||
* Eventy z _booking_source = 'ical_import_global' są pomijane (anti-loop —
|
||||
* nie wysyłamy z powrotem do Google tego, co stamtąd przyszło).
|
||||
*/
|
||||
private static function output_ics( $yacht ) {
|
||||
private static function output_global_ics() {
|
||||
$bookings = get_posts(
|
||||
array(
|
||||
'post_type' => 'yacht_booking',
|
||||
'posts_per_page' => -1,
|
||||
'post_status' => 'publish',
|
||||
'meta_query' => array(
|
||||
'relation' => 'AND',
|
||||
array(
|
||||
'key' => '_booking_yacht_id',
|
||||
'value' => $yacht->ID,
|
||||
),
|
||||
array(
|
||||
'key' => '_booking_status',
|
||||
'value' => 'cancelled',
|
||||
@@ -156,7 +144,7 @@ class ICal_Feed {
|
||||
$domain = wp_parse_url( home_url(), PHP_URL_HOST );
|
||||
|
||||
header( 'Content-Type: text/calendar; charset=utf-8' );
|
||||
header( 'Content-Disposition: inline; filename="' . sanitize_file_name( $yacht->post_title ) . '.ics"' );
|
||||
header( 'Content-Disposition: inline; filename="yachts-all.ics"' );
|
||||
header( 'Cache-Control: no-cache, must-revalidate' );
|
||||
|
||||
$lines = array();
|
||||
@@ -165,10 +153,32 @@ class ICal_Feed {
|
||||
$lines[] = 'PRODID:-//YachtBooking//NONSGML v1.0//PL';
|
||||
$lines[] = 'CALSCALE:GREGORIAN';
|
||||
$lines[] = 'METHOD:PUBLISH';
|
||||
$lines[] = 'X-WR-CALNAME:' . self::escape_ical( $yacht->post_title . ' - ' . $site_name );
|
||||
$lines[] = 'X-WR-CALNAME:' . self::escape_ical(
|
||||
sprintf(
|
||||
/* translators: %s: site name */
|
||||
__( 'Wszystkie jachty - %s', 'yacht-booking' ),
|
||||
$site_name
|
||||
)
|
||||
);
|
||||
$lines[] = 'X-WR-TIMEZONE:Europe/Warsaw';
|
||||
|
||||
foreach ( $bookings as $booking ) {
|
||||
// Anti-loop: pomiń eventy które zostały zaimportowane z globalnego GCal.
|
||||
$source = get_post_meta( $booking->ID, '_booking_source', true );
|
||||
if ( ICal_Import::GLOBAL_IMPORT_SOURCE === $source ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$yacht_id = (int) Booking::get_yacht_id( $booking->ID );
|
||||
if ( ! $yacht_id ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$yacht = get_post( $yacht_id );
|
||||
if ( ! $yacht ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$start = Booking::get_start_date( $booking->ID );
|
||||
$end = Booking::get_end_date( $booking->ID );
|
||||
$status = Booking::get_status( $booking->ID );
|
||||
@@ -178,10 +188,11 @@ class ICal_Feed {
|
||||
continue;
|
||||
}
|
||||
|
||||
// iCal DTEND for all-day events is exclusive
|
||||
// iCal DTEND for all-day events is exclusive.
|
||||
$end_exclusive = gmdate( 'Ymd', strtotime( $end . ' +1 day' ) );
|
||||
$created = get_the_date( 'Ymd\THis\Z', $booking );
|
||||
|
||||
// Prefiks nazwy jachtu — kluczowy dla późniejszego importu po prefiksie.
|
||||
$summary = sprintf( '%s - %s', $yacht->post_title, $name );
|
||||
if ( 'pending' === $status ) {
|
||||
$summary = '[' . __( 'Oczekująca', 'yacht-booking' ) . '] ' . $summary;
|
||||
|
||||
@@ -24,23 +24,31 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
class ICal_Import {
|
||||
|
||||
/**
|
||||
* Booking source identifier for iCal imports.
|
||||
* Booking source identifier for iCal imports (globalny — wspólny GCal,
|
||||
* podział po prefiksie nazwy jachtu w SUMMARY).
|
||||
*/
|
||||
const IMPORT_SOURCE = 'ical_import';
|
||||
const GLOBAL_IMPORT_SOURCE = 'ical_import_global';
|
||||
|
||||
/**
|
||||
* Separator między prefiksem nazwy jachtu a resztą tytułu eventu.
|
||||
*
|
||||
* Przykład SUMMARY: "Maja - Kowalski 5 osób" → prefix="Maja", reszta="Kowalski 5 osób".
|
||||
*/
|
||||
const SUMMARY_SEPARATOR = ' - ';
|
||||
|
||||
/**
|
||||
* Register cron actions
|
||||
*/
|
||||
public static function register() {
|
||||
add_action( 'yacht_booking_ical_import', array( __CLASS__, 'run_import' ) );
|
||||
add_action( 'yacht_booking_ical_global_import', array( __CLASS__, 'run_global_import' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup cron schedule
|
||||
*/
|
||||
public static function setup_cron() {
|
||||
if ( ! wp_next_scheduled( 'yacht_booking_ical_import' ) ) {
|
||||
wp_schedule_event( time(), 'hourly', 'yacht_booking_ical_import' );
|
||||
if ( ! wp_next_scheduled( 'yacht_booking_ical_global_import' ) ) {
|
||||
wp_schedule_event( time(), 'hourly', 'yacht_booking_ical_global_import' );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,57 +56,26 @@ class ICal_Import {
|
||||
* Clear cron
|
||||
*/
|
||||
public static function clear_cron() {
|
||||
wp_clear_scheduled_hook( 'yacht_booking_ical_import' );
|
||||
wp_clear_scheduled_hook( 'yacht_booking_ical_global_import' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Run import for all yachts that have an iCal URL configured.
|
||||
* Globalny iCal import — pobiera jeden URL kalendarza Google z ustawień
|
||||
* globalnych, parsuje eventy i przypisuje je do jachtów po prefiksie w SUMMARY.
|
||||
*
|
||||
* Format SUMMARY: "{nazwa_jachtu_lub_alias} - {opis}".
|
||||
* Eventy bez separatora lub bez dopasowanego jachtu są ignorowane (logowane).
|
||||
*
|
||||
* @return bool True przy sukcesie HTTP, false przy błędzie pobrania/braku URL.
|
||||
*/
|
||||
public static function run_import() {
|
||||
$yachts = get_posts(
|
||||
array(
|
||||
'post_type' => 'yacht',
|
||||
'posts_per_page' => -1,
|
||||
'fields' => 'ids',
|
||||
)
|
||||
);
|
||||
public static function run_global_import() {
|
||||
$url = get_option( 'yacht_booking_global_ical_import_url', '' );
|
||||
$url = is_string( $url ) ? trim( $url ) : '';
|
||||
|
||||
foreach ( $yachts as $yacht_id ) {
|
||||
$url = self::get_import_url( $yacht_id );
|
||||
if ( $url ) {
|
||||
self::import_for_yacht( $yacht_id, $url );
|
||||
}
|
||||
if ( empty( $url ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get iCal import URL for a yacht.
|
||||
*
|
||||
* @param int $yacht_id Yacht ID.
|
||||
* @return string
|
||||
*/
|
||||
public static function get_import_url( $yacht_id ) {
|
||||
return get_post_meta( $yacht_id, '_yacht_ical_import_url', true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set iCal import URL for a yacht.
|
||||
*
|
||||
* @param int $yacht_id Yacht ID.
|
||||
* @param string $url iCal URL.
|
||||
*/
|
||||
public static function set_import_url( $yacht_id, $url ) {
|
||||
update_post_meta( $yacht_id, '_yacht_ical_import_url', esc_url_raw( $url ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Import events from iCal URL for a specific yacht.
|
||||
*
|
||||
* @param int $yacht_id Yacht ID.
|
||||
* @param string $url iCal URL.
|
||||
* @return bool
|
||||
*/
|
||||
public static function import_for_yacht( $yacht_id, $url ) {
|
||||
$response = wp_remote_get(
|
||||
$url,
|
||||
array(
|
||||
@@ -108,19 +85,26 @@ class ICal_Import {
|
||||
);
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
self::log( sprintf( 'iCal fetch failed for yacht #%d: %s', $yacht_id, $response->get_error_message() ), 'error' );
|
||||
self::log( sprintf( 'Global iCal fetch failed: %s', $response->get_error_message() ), 'error' );
|
||||
return false;
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body( $response );
|
||||
if ( empty( $body ) ) {
|
||||
self::log( sprintf( 'iCal empty response for yacht #%d', $yacht_id ), 'error' );
|
||||
self::log( 'Global iCal: empty response body', 'error' );
|
||||
return false;
|
||||
}
|
||||
|
||||
$events = self::parse_ics( $body );
|
||||
$events = self::parse_ics( $body );
|
||||
$yacht_map = self::build_yacht_lookup_map();
|
||||
|
||||
$existing_map = self::get_existing_import_map( $yacht_id );
|
||||
if ( empty( $yacht_map ) ) {
|
||||
self::log( 'Global iCal: no yachts in DB — nothing to match', 'error' );
|
||||
update_option( 'yacht_booking_global_ical_last_import', current_time( 'mysql' ) );
|
||||
return true;
|
||||
}
|
||||
|
||||
$existing_map = self::get_existing_global_import_map();
|
||||
$seen_uids = array();
|
||||
|
||||
foreach ( $events as $event ) {
|
||||
@@ -128,39 +112,198 @@ class ICal_Import {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip past events
|
||||
// Skip past events.
|
||||
if ( strtotime( $event['end'] ) < time() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$seen_uids[] = $event['uid'];
|
||||
$booking_id = isset( $existing_map[ $event['uid'] ] ) ? (int) $existing_map[ $event['uid'] ] : 0;
|
||||
$booking_id = self::upsert_booking( $yacht_id, $event, $booking_id );
|
||||
$summary = isset( $event['summary'] ) ? (string) $event['summary'] : '';
|
||||
$yacht_id = self::match_yacht_by_prefix( $summary, $yacht_map );
|
||||
|
||||
if ( ! $yacht_id ) {
|
||||
self::log( sprintf( 'Global iCal: skip event "%s" — no yacht match for prefix', $summary ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
$seen_uids[] = $event['uid'];
|
||||
$existing_id = isset( $existing_map[ $event['uid'] ] ) ? (int) $existing_map[ $event['uid'] ] : 0;
|
||||
|
||||
$booking_id = self::upsert_global_booking( $yacht_id, $event, $existing_id );
|
||||
|
||||
if ( ! $booking_id ) {
|
||||
self::log( sprintf( 'Failed to upsert iCal event %s for yacht #%d', $event['uid'], $yacht_id ), 'error' );
|
||||
self::log( sprintf( 'Global iCal: failed to upsert event %s', $event['uid'] ), 'error' );
|
||||
}
|
||||
}
|
||||
|
||||
// Remove stale imports (events deleted from external calendar)
|
||||
// Stale cleanup — usuń bookingi których UID nie ma już w feedzie.
|
||||
foreach ( $existing_map as $uid => $booking_id ) {
|
||||
if ( ! in_array( $uid, $seen_uids, true ) ) {
|
||||
Availability::clear_booking_availability( $booking_id );
|
||||
\YachtBooking\Availability::clear_booking_availability( $booking_id );
|
||||
wp_delete_post( $booking_id, true );
|
||||
}
|
||||
}
|
||||
|
||||
update_post_meta( $yacht_id, '_yacht_ical_last_import', current_time( 'mysql' ) );
|
||||
update_option( 'yacht_booking_global_ical_last_import', current_time( 'mysql' ) );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Buduje mapę: lowercase(alias|post_title) => yacht_id.
|
||||
*
|
||||
* Alias (`_yacht_gcal_alias`) ma priorytet nad post_title. Klucze są
|
||||
* znormalizowane przez mb_strtolower + trim, dla matchowania case-insensitive
|
||||
* i niezależnego od białych znaków.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function build_yacht_lookup_map() {
|
||||
$yachts = get_posts(
|
||||
array(
|
||||
'post_type' => 'yacht',
|
||||
'post_status' => 'publish',
|
||||
'posts_per_page' => -1,
|
||||
)
|
||||
);
|
||||
|
||||
$map = array();
|
||||
foreach ( $yachts as $yacht ) {
|
||||
$alias = \YachtBooking\Yacht::get_gcal_alias( $yacht->ID );
|
||||
$key = '' !== trim( (string) $alias ) ? $alias : $yacht->post_title;
|
||||
$key = mb_strtolower( trim( (string) $key ) );
|
||||
|
||||
if ( '' === $key ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Nie nadpisuj — w razie kolizji wygrywa pierwszy. Kolizje są
|
||||
// wpisem do logu w czasie matchowania (nie tutaj — bezgłośnie pierwszy).
|
||||
if ( ! isset( $map[ $key ] ) ) {
|
||||
$map[ $key ] = (int) $yacht->ID;
|
||||
}
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wyciąga prefiks (przed pierwszym " - ") z SUMMARY i dopasowuje do jachtu
|
||||
* w mapie (case-insensitive).
|
||||
*
|
||||
* @param string $summary SUMMARY eventu.
|
||||
* @param array $yacht_map Mapa lowercase(klucz) => yacht_id.
|
||||
* @return int 0 gdy brak dopasowania.
|
||||
*/
|
||||
protected static function match_yacht_by_prefix( $summary, $yacht_map ) {
|
||||
if ( '' === $summary ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$pos = mb_strpos( $summary, self::SUMMARY_SEPARATOR );
|
||||
if ( false === $pos ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$prefix = mb_substr( $summary, 0, $pos );
|
||||
$prefix = mb_strtolower( trim( $prefix ) );
|
||||
|
||||
if ( '' === $prefix ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return isset( $yacht_map[ $prefix ] ) ? (int) $yacht_map[ $prefix ] : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zwraca mapę istniejących globalnych importów: uid => booking_id.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function get_existing_global_import_map() {
|
||||
$bookings = get_posts(
|
||||
array(
|
||||
'post_type' => 'yacht_booking',
|
||||
'post_status' => 'publish',
|
||||
'posts_per_page' => -1,
|
||||
'fields' => 'ids',
|
||||
'meta_query' => array(
|
||||
array(
|
||||
'key' => '_booking_source',
|
||||
'value' => self::GLOBAL_IMPORT_SOURCE,
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$map = array();
|
||||
foreach ( $bookings as $booking_id ) {
|
||||
$uid = get_post_meta( $booking_id, '_ical_event_uid', true );
|
||||
if ( $uid ) {
|
||||
$map[ $uid ] = (int) $booking_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tworzy lub aktualizuje booking placeholder z globalnego importu.
|
||||
*
|
||||
* @param int $yacht_id Yacht ID.
|
||||
* @param array $event Parsed event data.
|
||||
* @param int $existing_id Existing booking ID (0 dla nowego).
|
||||
* @return int|false
|
||||
*/
|
||||
protected static function upsert_global_booking( $yacht_id, $event, $existing_id = 0 ) {
|
||||
$summary = ! empty( $event['summary'] ) ? sanitize_text_field( $event['summary'] ) : __( 'Blokada Google Calendar', 'yacht-booking' );
|
||||
$start_date = $event['start'];
|
||||
$end_date = $event['end'];
|
||||
|
||||
$post_data = array(
|
||||
'post_type' => 'yacht_booking',
|
||||
'post_status' => 'publish',
|
||||
'post_title' => sprintf(
|
||||
/* translators: %s: event summary */
|
||||
__( 'GCal: %s', 'yacht-booking' ),
|
||||
$summary
|
||||
),
|
||||
);
|
||||
|
||||
if ( $existing_id > 0 ) {
|
||||
$post_data['ID'] = $existing_id;
|
||||
$booking_id = wp_update_post( $post_data, true );
|
||||
} else {
|
||||
$booking_id = wp_insert_post( $post_data, true );
|
||||
}
|
||||
|
||||
if ( is_wp_error( $booking_id ) || ! $booking_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
update_post_meta( $booking_id, '_booking_yacht_id', (int) $yacht_id );
|
||||
update_post_meta( $booking_id, '_booking_start_date', $start_date );
|
||||
update_post_meta( $booking_id, '_booking_end_date', $end_date );
|
||||
update_post_meta( $booking_id, '_booking_status', 'confirmed' );
|
||||
update_post_meta( $booking_id, '_booking_customer_name', __( 'Google Calendar (import)', 'yacht-booking' ) );
|
||||
update_post_meta( $booking_id, '_booking_customer_email', '' );
|
||||
update_post_meta( $booking_id, '_booking_customer_phone', '' );
|
||||
update_post_meta( $booking_id, '_booking_total_price', 0 );
|
||||
update_post_meta( $booking_id, '_booking_source', self::GLOBAL_IMPORT_SOURCE );
|
||||
update_post_meta( $booking_id, '_ical_event_uid', $event['uid'] );
|
||||
update_post_meta( $booking_id, '_booking_notes', $summary );
|
||||
|
||||
\YachtBooking\Availability::clear_booking_availability( $booking_id );
|
||||
\YachtBooking\Availability::mark_as_booked( $yacht_id, $start_date, $end_date, $booking_id );
|
||||
|
||||
return (int) $booking_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse .ics content into array of events.
|
||||
*
|
||||
* @param string $ics_content Raw .ics content.
|
||||
* @return array
|
||||
*/
|
||||
private static function parse_ics( $ics_content ) {
|
||||
protected static function parse_ics( $ics_content ) {
|
||||
$events = array();
|
||||
$lines = preg_split( '/\r\n|\r|\n/', $ics_content );
|
||||
$in_event = false;
|
||||
@@ -277,106 +420,6 @@ class ICal_Import {
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get existing imported bookings map: uid => booking_id.
|
||||
*
|
||||
* @param int $yacht_id Yacht ID.
|
||||
* @return array
|
||||
*/
|
||||
private static function get_existing_import_map( $yacht_id ) {
|
||||
$bookings = get_posts(
|
||||
array(
|
||||
'post_type' => 'yacht_booking',
|
||||
'post_status' => 'publish',
|
||||
'posts_per_page' => -1,
|
||||
'fields' => 'ids',
|
||||
'meta_query' => array(
|
||||
'relation' => 'AND',
|
||||
array(
|
||||
'key' => '_booking_source',
|
||||
'value' => self::IMPORT_SOURCE,
|
||||
),
|
||||
array(
|
||||
'key' => '_booking_yacht_id',
|
||||
'value' => (int) $yacht_id,
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$map = array();
|
||||
foreach ( $bookings as $booking_id ) {
|
||||
$uid = get_post_meta( $booking_id, '_ical_event_uid', true );
|
||||
if ( $uid ) {
|
||||
$map[ $uid ] = (int) $booking_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or update imported booking placeholder.
|
||||
*
|
||||
* @param int $yacht_id Yacht ID.
|
||||
* @param array $event Parsed event data.
|
||||
* @param int $existing_id Existing booking ID (0 for new).
|
||||
* @return int|false
|
||||
*/
|
||||
private static function upsert_booking( $yacht_id, $event, $existing_id = 0 ) {
|
||||
$summary = ! empty( $event['summary'] ) ? sanitize_text_field( $event['summary'] ) : __( 'Blokada iCal', 'yacht-booking' );
|
||||
$start_date = $event['start'];
|
||||
$end_date = $event['end'];
|
||||
|
||||
$post_data = array(
|
||||
'post_type' => 'yacht_booking',
|
||||
'post_status' => 'publish',
|
||||
'post_title' => sprintf(
|
||||
/* translators: %s: event summary */
|
||||
__( 'Import iCal: %s', 'yacht-booking' ),
|
||||
$summary
|
||||
),
|
||||
);
|
||||
|
||||
if ( $existing_id > 0 ) {
|
||||
$post_data['ID'] = $existing_id;
|
||||
$booking_id = wp_update_post( $post_data, true );
|
||||
} else {
|
||||
$booking_id = wp_insert_post( $post_data, true );
|
||||
}
|
||||
|
||||
if ( is_wp_error( $booking_id ) || ! $booking_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
update_post_meta( $booking_id, '_booking_yacht_id', (int) $yacht_id );
|
||||
update_post_meta( $booking_id, '_booking_start_date', $start_date );
|
||||
update_post_meta( $booking_id, '_booking_end_date', $end_date );
|
||||
update_post_meta( $booking_id, '_booking_status', 'confirmed' );
|
||||
update_post_meta( $booking_id, '_booking_customer_name', __( 'Import iCal', 'yacht-booking' ) );
|
||||
update_post_meta( $booking_id, '_booking_customer_email', '' );
|
||||
update_post_meta( $booking_id, '_booking_customer_phone', '' );
|
||||
update_post_meta( $booking_id, '_booking_total_price', 0 );
|
||||
update_post_meta( $booking_id, '_booking_source', self::IMPORT_SOURCE );
|
||||
update_post_meta( $booking_id, '_ical_event_uid', $event['uid'] );
|
||||
update_post_meta( $booking_id, '_booking_notes', $summary );
|
||||
|
||||
Availability::clear_booking_availability( $booking_id );
|
||||
Availability::mark_as_booked( $yacht_id, $start_date, $end_date, $booking_id );
|
||||
|
||||
return (int) $booking_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get last import time for yacht.
|
||||
*
|
||||
* @param int $yacht_id Yacht ID.
|
||||
* @return string
|
||||
*/
|
||||
public static function get_last_import_time( $yacht_id ) {
|
||||
return get_post_meta( $yacht_id, '_yacht_ical_last_import', true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Log message.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user