array( 'name' => __( 'Events', 'seathive' ), 'singular_name' => __( 'Event', 'seathive' ), 'add_new_item' => __( 'Add New Event', 'seathive' ), 'edit_item' => __( 'Edit Event', 'seathive' ), ), 'public' => true, 'show_in_menu' => 'seatt-main', 'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt' ), 'show_in_rest' => true, 'menu_icon' => 'dashicons-tickets-alt', 'rewrite' => array( 'slug' => 'events' ), ) ); } /* --------------------------------------------------------------- * Event Settings meta box: event date, free/paid booking, and * default price per seat category (used as a reference — and as a * pre-fill — when building the chart's seat prices). * ------------------------------------------------------------- */ const BANNER_MAX_BYTES = 2097152; // 2 MB /** Banner guideline shown under the featured-image box. */ public static function banner_note_text() { return __( 'Recommended size: 1920 × 1080 px (16:9), JPG or WebP. Maximum file size 2 MB — larger files are rejected. Keep important text (event name, date, logo) in the centre, about 10% away from the top and bottom edges.', 'seathive' ); } public static function banner_too_big_message( $bytes ) { return sprintf( /* translators: %s: file size, e.g. 3.4 MB */ __( 'This image is %s. Event images can be at most 2 MB — please make it smaller (for example with squoosh.app or tinypng.com) and upload it again.', 'seathive' ), number_format_i18n( $bytes / 1048576, 1 ) . ' MB' ); } /** Uploads made from an event's edit screen (classic media modal or block editor). */ public function limit_banner_upload( $file ) { $post_id = intval( $_REQUEST['post_id'] ?? ( $_REQUEST['post'] ?? 0 ) ); // phpcs:ignore WordPress.Security.NonceVerification if ( ! $post_id || 'seatt_event' !== get_post_type( $post_id ) || empty( $file['size'] ) ) { return $file; } if ( 0 === strpos( (string) ( $file['type'] ?? '' ), 'image/' ) && (int) $file['size'] > self::BANNER_MAX_BYTES ) { $file['error'] = self::banner_too_big_message( (int) $file['size'] ); } return $file; } private static function attachment_bytes( $attachment_id ) { $path = $attachment_id ? get_attached_file( (int) $attachment_id ) : ''; return ( $path && file_exists( $path ) ) ? (int) filesize( $path ) : 0; } /** Block editor: picking a too-large library image as banner shows an error. */ public function limit_banner_rest( $prepared, $request ) { $media = $request->get_param( 'featured_media' ); if ( $media ) { $bytes = self::attachment_bytes( (int) $media ); if ( $bytes > self::BANNER_MAX_BYTES ) { return new WP_Error( 'seatt_banner_too_big', self::banner_too_big_message( $bytes ), array( 'status' => 400 ) ); } } return $prepared; } /** Classic editor / any other path: never store a too-large banner. */ public function limit_banner_meta( $check, $object_id, $meta_key, $meta_value ) { if ( '_thumbnail_id' !== $meta_key || 'seatt_event' !== get_post_type( $object_id ) ) { return $check; } return self::attachment_bytes( (int) $meta_value ) > self::BANNER_MAX_BYTES ? false : $check; } /** Classic editor: note under "Set featured image". */ public function banner_size_note( $html, $post_id ) { if ( 'seatt_event' !== get_post_type( $post_id ) ) { return $html; } return $html . '
' . esc_html( self::banner_note_text() ) . '
'; } /** Block editor: the same note under the Featured image panel. */ public function enqueue_media_for_event( $hook ) { $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; if ( $screen && 'seatt_event' === $screen->post_type && in_array( $hook, array( 'post.php', 'post-new.php' ), true ) ) { wp_enqueue_media(); wp_enqueue_script( 'jquery-ui-sortable' ); } } /** "Couldn't remove category X — it has sold seats." */ public function tickets_notice() { $m = get_transient( 'seatt_tickets_msg_' . get_current_user_id() ); if ( $m ) { delete_transient( 'seatt_tickets_msg_' . get_current_user_id() ); echo '' . esc_html( $m ) . '
' . esc_html( sprintf( /* translators: %s: value */ __( 'These categories were kept because they have sold seats: %s. Move those seats to another category in the Chart Builder first.', 'seathive' ), implode( ', ', (array) $kept ) ) ) . '
' . esc_html__( 'Save or publish this event first — the shortcode will appear here once it has an ID to point to.', 'seathive' ) . '
'; return; } $shortcode = '[seatt_booking event_id="' . $post->ID . '"]'; ?>get_post_meta( $event_id, '_seatt_event_date', true ), 'booking_type' => get_post_meta( $event_id, '_seatt_booking_type', true ) ?: 'paid', 'price_standard' => get_post_meta( $event_id, '_seatt_price_standard', true ), 'price_vip' => get_post_meta( $event_id, '_seatt_price_vip', true ), 'price_reserved' => get_post_meta( $event_id, '_seatt_price_reserved', true ), 'price_standing' => get_post_meta( $event_id, '_seatt_price_standing', true ), ); } public function render_meta_box( $post ) { // One date of a multi-date event: its settings come from the main event. if ( class_exists( 'SEATT_Series' ) && SEATT_Series::render_child_box( $post ) ) { return; } wp_nonce_field( 'seatt_event_settings_save', 'seatt_event_settings_nonce' ); $s = self::get_settings( $post->ID ); $gateway = get_option( 'seatt_payment_gateway', 'manual' ); $gateway_labels = array( 'manual' => __( 'Cash', 'seathive' ), 'xendit' => 'Xendit', 'stripe' => 'Stripe', 'paypal' => 'PayPal', 'doku' => 'DOKU' ); ?>
–
' . esc_html( $gateway_labels[ $gateway ] ?? $gateway ) . '', '' . esc_html__( 'Payment Settings', 'seathive' ) . '' ); ?>
' . esc_html( $active_currency_code ) . '', esc_html( $active_currency_symbol ), '' . esc_html__( 'Settings → Store Setting', 'seathive' ) . '' ); ?>
ID, $active_currency_symbol ); ?>' . esc_html__( 'This event is cancelled.', 'seathive' ) . '
'; echo '' . esc_html( sprintf( /* translators: %s: value */ __( 'Cancelled on %s', 'seathive' ), mysql2date( 'j M Y H:i', get_post_meta( $post->ID, '_seatt_cancelled_at', true ) ) ) ) . '
'; echo '' . esc_html__( 'Manage refunds', 'seathive' ) . '
'; return; } ?> ID ) . '); add(\'reason\', document.getElementById(\'esm-cancel-reason\').value); add(\'_wpnonce\', ' . ( wp_json_encode( wp_create_nonce( 'seatt_cancel_event_' . $post->ID ) ) ) . '); document.body.appendChild(f); f.submit(); }); ' ); ?> '_seatt_event_time', 'seatt_event_end_time' => '_seatt_event_end_time' ) as $f => $k ) { $t = sanitize_text_field( wp_unslash( $_POST[ $f ] ?? '' ) ); update_post_meta( $post_id, $k, preg_match( '/^\d{2}:\d{2}$/', $t ) ? $t : '' ); } } if ( isset( $_POST['seatt_event_date'] ) ) { update_post_meta( $post_id, '_seatt_event_date', sanitize_text_field( wp_unslash( $_POST['seatt_event_date'] ) ) ); } if ( isset( $_POST['seatt_hold_minutes'] ) ) { $hold = absint( wp_unslash( $_POST['seatt_hold_minutes'] ) ); update_post_meta( $post_id, '_seatt_hold_minutes', $hold > 0 ? max( SEATT_DB::HOLD_MINUTES_MIN, min( SEATT_DB::HOLD_MINUTES_MAX, $hold ) ) : '' ); } if ( isset( $_POST['seatt_max_seats'] ) ) { $max = (int) $_POST['seatt_max_seats']; update_post_meta( $post_id, '_seatt_max_seats', $max > 0 ? min( 100, $max ) : '' ); update_post_meta( $post_id, '_seatt_max_seats_scope', 'person' === sanitize_key( wp_unslash( $_POST['seatt_max_seats_scope'] ?? '' ) ) ? 'person' : 'order' ); } if ( isset( $_POST['seatt_earlybird_value'] ) ) { update_post_meta( $post_id, '_seatt_earlybird_value', max( 0, (float) $_POST['seatt_earlybird_value'] ) ); update_post_meta( $post_id, '_seatt_earlybird_type', 'amount' === sanitize_key( wp_unslash( $_POST['seatt_earlybird_type'] ?? '' ) ) ? 'amount' : 'percent' ); $until = sanitize_text_field( wp_unslash( $_POST['seatt_earlybird_until'] ?? '' ) ); update_post_meta( $post_id, '_seatt_earlybird_until', preg_match( '/^\d{4}-\d{2}-\d{2}$/', $until ) ? $until : '' ); } if ( isset( $_POST['seatt_booking_type'] ) ) { $type = 'free' === sanitize_key( wp_unslash( $_POST['seatt_booking_type'] ) ) ? 'free' : 'paid'; update_post_meta( $post_id, '_seatt_booking_type', $type ); } if ( isset( $_POST['seatt_sales_mode'] ) ) { $tmsg = SEATT_Tickets::save( $post_id, sanitize_key( wp_unslash( $_POST['seatt_sales_mode'] ) ), wp_unslash( $_POST['seatt_ticket_types'] ?? '[]' ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- JSON; every field is sanitized in SEATT_Tickets::clean() if ( $tmsg ) { set_transient( 'seatt_tickets_msg_' . get_current_user_id(), $tmsg, 120 ); } } if ( isset( $_POST['seatt_categories'] ) && ! SEATT_Tickets::is_ticket_mode( $post_id ) ) { $res = SEATT_Categories::save( $post_id, wp_unslash( $_POST['seatt_categories'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- JSON; every field is sanitized in SEATT_Categories::save() if ( ! empty( $res['kept'] ) ) { set_transient( 'seatt_cats_kept_' . get_current_user_id(), $res['kept'], 120 ); } } foreach ( array( 'seatt_price_reserved', 'seatt_price_standing' ) as $field ) { if ( isset( $_POST[ $field ] ) ) { update_post_meta( $post_id, '_' . $field, floatval( $_POST[ $field ] ) ); } } /** * Saves the extra Event Settings sections (nonce already checked). * * @param int $post_id The event. */ do_action( 'seatt_event_settings_save', $post_id ); } /* --------------------------------------------------------------- * Events list: Date column + dark mode toggle * ------------------------------------------------------------- */ public function add_columns( $columns ) { $new = array(); foreach ( $columns as $key => $label ) { $new[ $key ] = $label; if ( 'title' === $key ) { $new['seatt_event_date'] = __( 'Event Date', 'seathive' ); $new['seatt_booking_type'] = __( 'Booking', 'seathive' ); } } return $new; } public function render_column( $column, $post_id ) { if ( 'seatt_event_date' === $column ) { $date = get_post_meta( $post_id, '_seatt_event_date', true ); echo $date ? esc_html( mysql2date( 'j M Y', $date ) ) : '—'; } elseif ( 'seatt_booking_type' === $column ) { $type = get_post_meta( $post_id, '_seatt_booking_type', true ) ?: 'paid'; echo 'free' === $type ? '' . esc_html__( 'Free', 'seathive' ) . '' : '' . esc_html__( 'Paid', 'seathive' ) . ''; } } public function sortable_columns( $columns ) { $columns['seatt_event_date'] = 'seatt_event_date'; return $columns; } public function sort_by_event_date( $query ) { if ( ! is_admin() || ! $query->is_main_query() ) { return; } if ( 'seatt_event_date' === $query->get( 'orderby' ) ) { $query->set( 'meta_key', '_seatt_event_date' ); $query->set( 'orderby', 'meta_value' ); } } public function enqueue( $hook ) { global $post_type; if ( 'seatt_event' !== $post_type || ! in_array( $hook, array( 'edit.php', 'post.php', 'post-new.php' ), true ) ) { return; } // esm-shared.css/js used to also carry this screen's dark-mode // toggle — dark mode is now Chart Builder-only, so neither is // needed here anymore. } }