= the number already sold.', required: false ), new ToolProperty( name: 'price', type: PropertyType::NUMBER, description: 'New ticket price. Set to 0 for free.', required: false ), new ToolProperty( name: 'min_ticket', type: PropertyType::NUMBER, description: 'New minimum per-order quantity.', required: false ), new ToolProperty( name: 'max_ticket', type: PropertyType::NUMBER, description: 'New maximum per-order quantity.', required: false ), new ToolProperty( name: 'start_date', type: PropertyType::STRING, description: 'New sales start date in YYYY-MM-DD format.', required: false ), new ToolProperty( name: 'end_date', type: PropertyType::STRING, description: 'New sales end date in YYYY-MM-DD format.', required: false ), new ToolProperty( name: 'start_time', type: PropertyType::STRING, description: 'New sales start time in HH:MM:SS format (24-hour).', required: false ), new ToolProperty( name: 'end_time', type: PropertyType::STRING, description: 'New sales end time in HH:MM:SS format (24-hour).', required: false ), ]; } public function get_approval_label(): string { return 'Update Eventin Ticket'; } public function format_approval_summary(): string { $inputs = $this->getInputs(); $slug = $inputs['ticket_slug'] ?? '?'; $event_id = $inputs['event_id'] ?? '?'; $name = $inputs['ticket_name'] ?? ''; $parts = []; if ( $name ) { $parts[] = "name to `{$name}`"; } if ( isset( $inputs['price'] ) ) { $parts[] = "price to `{$inputs['price']}`"; } if ( isset( $inputs['available_tickets'] ) ) { $parts[] = "available to `{$inputs['available_tickets']}`"; } $change_str = ! empty( $parts ) ? ': ' . implode( ', ', $parts ) : ''; return "Update ticket `{$slug}` on event #{$event_id}{$change_str}"; } public function get_approval_inputs(): array { return $this->getInputs(); } public function __invoke( int $event_id, string $ticket_slug, ?string $ticket_name = null, ?int $available_tickets = null, ?float $price = null, ?int $min_ticket = null, ?int $max_ticket = null, ?string $start_date = null, ?string $end_date = null, ?string $start_time = null, ?string $end_time = null ): array { $check = $this->guard( 'etn_manage_event' ); if ( $check ) { return $check; } try { if ( $event_id <= 0 ) { return [ 'error' => 'event_id must be a positive integer.' ]; } $post = get_post( $event_id ); if ( ! $post || 'etn' !== $post->post_type ) { return [ 'error' => "No Eventin event found with ID {$event_id}." ]; } if ( empty( trim( $ticket_slug ) ) ) { return [ 'error' => 'ticket_slug is required.' ]; } $sanitized_slug = sanitize_title( $ticket_slug ); if ( null !== $start_date && '' !== trim( $start_date ) ) { $parsed = \DateTime::createFromFormat( 'Y-m-d', $start_date ); if ( ! $parsed || $parsed->format( 'Y-m-d' ) !== $start_date ) { return [ 'error' => 'start_date must be in YYYY-MM-DD format.' ]; } } if ( null !== $end_date && '' !== trim( $end_date ) ) { $parsed = \DateTime::createFromFormat( 'Y-m-d', $end_date ); if ( ! $parsed || $parsed->format( 'Y-m-d' ) !== $end_date ) { return [ 'error' => 'end_date must be in YYYY-MM-DD format.' ]; } } if ( null !== $start_date && null !== $end_date ) { $s = trim( $start_date ); $e = trim( $end_date ); if ( '' !== $s && '' !== $e && $e < $s ) { return [ 'error' => 'end_date must be on or after start_date.' ]; } } if ( null !== $start_time && '' !== trim( $start_time ) ) { $parsed = \DateTime::createFromFormat( 'H:i:s', $start_time ); if ( ! $parsed || $parsed->format( 'H:i:s' ) !== $start_time ) { $parsed12 = \DateTime::createFromFormat( 'h:i:s A', $start_time ); if ( ! $parsed12 ) { return [ 'error' => 'start_time must be in HH:MM:SS or HH:MM:SS AM/PM format.' ]; } } } if ( null !== $end_time && '' !== trim( $end_time ) ) { $parsed = \DateTime::createFromFormat( 'H:i:s', $end_time ); if ( ! $parsed || $parsed->format( 'H:i:s' ) !== $end_time ) { $parsed12 = \DateTime::createFromFormat( 'h:i:s A', $end_time ); if ( ! $parsed12 ) { return [ 'error' => 'end_time must be in HH:MM:SS or HH:MM:SS AM/PM format.' ]; } } } $existing_variations_raw = get_post_meta( $event_id, 'etn_ticket_variations', true ); $existing_variations = []; if ( ! empty( $existing_variations_raw ) ) { $decoded = is_string( $existing_variations_raw ) ? json_decode( $existing_variations_raw, true ) : $existing_variations_raw; $existing_variations = is_array( $decoded ) ? $decoded : []; } $ticket_index = null; foreach ( $existing_variations as $index => $ticket ) { if ( isset( $ticket['etn_ticket_slug'] ) && $ticket['etn_ticket_slug'] === $sanitized_slug ) { $ticket_index = $index; break; } } if ( null === $ticket_index ) { return [ 'error' => "No ticket with slug `{$sanitized_slug}` found on event #{$event_id}. " . 'Use eventin-create-ticket to add it first.', ]; } $existing_ticket = $existing_variations[ $ticket_index ]; if ( null !== $available_tickets && $available_tickets < 0 ) { return [ 'error' => 'available_tickets must be a non-negative integer.' ]; } if ( null !== $available_tickets ) { $sold = (int) ( $existing_ticket['etn_sold_tickets'] ?? 0 ); if ( $available_tickets < $sold ) { return [ 'error' => "available_tickets ({$available_tickets}) cannot be less than " . "the number already sold ({$sold}).", ]; } } $updated_ticket = $existing_ticket; if ( null !== $ticket_name && '' !== trim( $ticket_name ) ) { $updated_ticket['etn_ticket_name'] = sanitize_text_field( $ticket_name ); } if ( null !== $available_tickets ) { $updated_ticket['etn_avaiilable_tickets'] = absint( $available_tickets ); } if ( null !== $price ) { $updated_ticket['etn_ticket_price'] = (float) $price; } if ( null !== $min_ticket ) { $updated_ticket['etn_min_ticket'] = absint( $min_ticket ); } if ( null !== $max_ticket ) { $updated_ticket['etn_max_ticket'] = absint( $max_ticket ); } if ( null !== $start_date ) { $updated_ticket['start_date'] = trim( $start_date ); } if ( null !== $end_date ) { $updated_ticket['end_date'] = trim( $end_date ); } if ( null !== $start_time ) { $updated_ticket['start_time'] = trim( $start_time ); } if ( null !== $end_time ) { $updated_ticket['end_time'] = trim( $end_time ); } $updated_variations = $existing_variations; $updated_variations[ $ticket_index ] = $updated_ticket; $body = [ 'title' => get_the_title( $event_id ), 'timezone' => get_post_meta( $event_id, 'event_timezone', true ) ?: 'UTC', 'start_date' => get_post_meta( $event_id, 'etn_start_date', true ) ?: gmdate( 'Y-m-d' ), 'end_date' => get_post_meta( $event_id, 'etn_end_date', true ) ?: gmdate( 'Y-m-d' ), 'start_time' => get_post_meta( $event_id, 'etn_start_time', true ) ?: '00:00:00', 'end_time' => get_post_meta( $event_id, 'etn_end_time', true ) ?: '00:00:00', 'ticket_variations' => $updated_variations, ]; $request = new \WP_REST_Request( 'POST' ); $request->set_header( 'content-type', 'application/json' ); $request->set_body( wp_json_encode( $body ) ); $request->set_url_params( [ 'id' => $event_id ] ); $controller = new \Eventin\Event\Api\EventController(); $response = $controller->update_item( $request ); if ( is_wp_error( $response ) ) { return [ 'error' => $response->get_error_message() ]; } return [ 'success' => true, 'event_id' => $event_id, 'ticket_slug' => $sanitized_slug, 'edit_url' => get_edit_post_link( $event_id, 'raw' ), 'message' => "Ticket `{$sanitized_slug}` on event #{$event_id} has been updated.", ]; } catch ( \Exception $e ) { Log::error( 'Eventin_Update_Ticket_Tool error', [ 'error' => $e->getMessage() ] ); return [ 'error' => 'Failed to update ticket: ' . $e->getMessage() ]; } } }