__('Events', 'ai-eshop-optimizer'), 'description' => __('Run events — launches, brand presentations, professional seminars — with a branded landing page, desktop/mobile creatives, a guest list, invitation emails and RSVP tracking.', 'ai-eshop-optimizer'), 'bullets' => array( __('Schedule with start, end and RSVP deadline', 'ai-eshop-optimizer'), __('Branded landing page with desktop + mobile creatives', 'ai-eshop-optimizer'), __('Associate brands, categories and products', 'ai-eshop-optimizer'), __('Invitation subject + rich-text invitation body', 'ai-eshop-optimizer'), __('Guest list with invited / confirmed / declined tracking', 'ai-eshop-optimizer'), ), ); } public function register_hooks() { if (!class_exists('AIEO_Event_CPT') && defined('AIEO_DIR') && file_exists(AIEO_DIR . 'includes/dmm/events/class-aieo-event-cpt.php')) { require_once AIEO_DIR . 'includes/dmm/events/class-aieo-event-cpt.php'; } if (class_exists('AIEO_Event_CPT')) { AIEO_Event_CPT::register(); } if (!class_exists('AIEO_Event_Participants') && defined('AIEO_DIR') && file_exists(AIEO_DIR . 'includes/dmm/events/class-aieo-event-participants.php')) { require_once AIEO_DIR . 'includes/dmm/events/class-aieo-event-participants.php'; } if (class_exists('AIEO_Event_Participants') && method_exists('AIEO_Event_Participants', 'register')) { AIEO_Event_Participants::register(); } if (!class_exists('AIEO_Event_RSVP') && defined('AIEO_DIR') && file_exists(AIEO_DIR . 'includes/dmm/events/class-aieo-event-rsvp.php')) { require_once AIEO_DIR . 'includes/dmm/events/class-aieo-event-rsvp.php'; } if (class_exists('AIEO_Event_RSVP') && method_exists('AIEO_Event_RSVP', 'register')) { AIEO_Event_RSVP::register(); } if (!class_exists('AIEO_Event_SelfReg') && defined('AIEO_DIR') && file_exists(AIEO_DIR . 'includes/dmm/events/class-aieo-event-selfreg.php')) { require_once AIEO_DIR . 'includes/dmm/events/class-aieo-event-selfreg.php'; } if (class_exists('AIEO_Event_SelfReg') && method_exists('AIEO_Event_SelfReg', 'register')) { AIEO_Event_SelfReg::register(); } add_action('wp_ajax_aieo_events_save', array($this, 'ajax_save')); add_action('wp_ajax_aieo_events_settings_save', array($this, 'ajax_save_settings')); add_action('admin_post_aieo_events_import', array($this, 'handle_import')); add_action('admin_post_aieo_events_participant_delete', array($this, 'handle_participant_delete')); add_action('admin_post_aieo_events_invites_send', array($this, 'handle_invites_send')); add_action('admin_post_aieo_events_invites_settings', array($this, 'handle_invites_settings')); add_action('admin_post_aieo_events_export', array($this, 'handle_export')); } private static function tab_url($args = array()) { $url = admin_url('admin.php?page=ai-eshop-dmm&dmm_tab=events'); return empty($args) ? $url : add_query_arg($args, $url); } public static function get_settings() { $s = get_option(self::SETTINGS_OPTION, array()); return is_array($s) ? $s : array(); } public function enqueue_admin_assets() { if (!self::is_aieo_pro_user()) { return; } wp_enqueue_media(); $css = 'assets/css/aieo-events-admin.css'; wp_enqueue_style('aieo-events-admin', plugins_url($css, AIEO_FILE), array(), file_exists(AIEO_DIR . $css) ? (string) filemtime(AIEO_DIR . $css) : '1'); if (class_exists('AIEO_Event_CPT') && method_exists('AIEO_Event_CPT', 'enqueue_picker_bundle')) { AIEO_Event_CPT::enqueue_picker_bundle(); } $handle = 'aieo-events-admin'; wp_enqueue_script( $handle, plugins_url('assets/js/aieo-events-admin.js', AIEO_FILE), array('jquery'), defined('AIEO_VERSION') ? AIEO_VERSION : '1.0', true ); wp_localize_script($handle, 'aieoEvents', array( 'ajaxurl' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce(self::NONCE), 'i18n' => array( 'select' => __('Select image', 'ai-eshop-optimizer'), 'use' => __('Use this image', 'ai-eshop-optimizer'), 'saving' => __('Saving…', 'ai-eshop-optimizer'), 'saved' => __('Saved.', 'ai-eshop-optimizer'), 'noname' => __('Please enter an event name.', 'ai-eshop-optimizer'), 'error' => __('Error', 'ai-eshop-optimizer'), 'failed' => __('Network error.', 'ai-eshop-optimizer'), ), )); } public function render_subtab() { $manage_id = isset($_GET['manage']) ? (int) $_GET['manage'] : 0; if ($manage_id > 0 && class_exists('AIEO_Event_CPT') && get_post_type($manage_id) === AIEO_Event_CPT::POST_TYPE) { $this->render_manage_screen($manage_id); return; } rooster_admin_band_open(array('cols' => 2)); list($open, $close) = AIEO_DMM_UI::card(array( 'anchor' => 'events-new-event', 'icon' => 'calendar-plus', 'title' => __('New event', 'ai-eshop-optimizer'), 'description' => __('Create an event, set its schedule and location, add a short description and desktop/mobile creatives, then compose the invitation. Each event becomes a landing page (use the native editor for the full agenda). Guest import, invitation send and RSVP tracking are managed per event.', 'ai-eshop-optimizer'), 'col' => 1, 'footer' => '' . '', )); echo $open; echo '
'; echo ''; echo '
'; echo AIEO_Kit::row(__('Name', 'ai-eshop-optimizer'), \Rooster\Admin\Ui::input('', '', array('id' => 'aieo-event-name', 'medium' => true, 'placeholder' => __('e.g. Spring Brand Showcase 2026', 'ai-eshop-optimizer'))), '', array('id' => 'aieo-event-name')); $event_row = \Rooster\Admin\Fields::compound( array( array('label' => __('Starts', 'ai-eshop-optimizer'), 'id' => 'aieo-event-start', 'control' => \Rooster\Admin\Ui::input('', '', array('id' => 'aieo-event-start', 'type' => 'datetime-local'))), array('label' => __('Ends', 'ai-eshop-optimizer'), 'id' => 'aieo-event-end', 'control' => \Rooster\Admin\Ui::input('', '', array('id' => 'aieo-event-end', 'type' => 'datetime-local'))), array('label' => __('RSVP deadline', 'ai-eshop-optimizer'), 'id' => 'aieo-event-rsvp-deadline', 'control' => \Rooster\Admin\Ui::input('', '', array('id' => 'aieo-event-rsvp-deadline', 'type' => 'datetime-local'))), ), array('label' => __('Schedule', 'ai-eshop-optimizer')) ); echo AIEO_Kit::row(__('Schedule', 'ai-eshop-optimizer'), $event_row, __('Optional. Visitors see a “coming soon” notice before the start and an “ended” message after the end; shop managers always see the live page. Leave start/end empty for an always-open event. The RSVP deadline is the date by which guests must respond.', 'ai-eshop-optimizer'), array('id' => 'aieo-event-schedule', 'group' => true)); echo AIEO_Kit::row(__('Location', 'ai-eshop-optimizer'), \Rooster\Admin\Ui::input('', '', array('id' => 'aieo-event-location', 'medium' => true, 'placeholder' => __('e.g. Athens Concert Hall, Hall B', 'ai-eshop-optimizer'))), '', array('id' => 'aieo-event-location')); echo AIEO_Kit::row(__('Map link', 'ai-eshop-optimizer'), \Rooster\Admin\Ui::input('', '', array('id' => 'aieo-event-map-url', 'type' => 'url', 'placeholder' => 'https://maps.google.com/…')), __('Optional Google Maps URL for directions. If empty, a Maps search link is built from the location.', 'ai-eshop-optimizer'), array('id' => 'aieo-event-map-url')); echo AIEO_Kit::row(__('Short description', 'ai-eshop-optimizer'), \Rooster\Admin\Ui::textarea('', '', array('id' => 'aieo-event-desc', 'rows' => 3)), __('A one-line summary. Use the native post editor for the full agenda after creating the event.', 'ai-eshop-optimizer'), array('id' => 'aieo-event-desc')); echo AIEO_Kit::row(__('Creatives', 'ai-eshop-optimizer'), '
' . $this->image_field('desktop', __('Desktop image', 'ai-eshop-optimizer')) . $this->image_field('mobile', __('Mobile image', 'ai-eshop-optimizer')) . '
', '', array('id' => 'aieo-event-creatives', 'group' => true)); echo '
'; ob_start(); echo '
'; echo AIEO_Kit::row(__('Brands', 'ai-eshop-optimizer'), '', __('Optional — associate brands so you can later monitor the products they pull.', 'ai-eshop-optimizer'), array('id' => 'aieo-event-brands')); echo AIEO_Kit::row(__('Categories', 'ai-eshop-optimizer'), '', __('Optional — associate product categories.', 'ai-eshop-optimizer'), array('id' => 'aieo-event-categories')); if (class_exists('AIEO_DMM_Product_Picker')) { $event_picker = AIEO_DMM_Product_Picker::render_field(array( 'name' => 'event_products', 'mode' => 'include', 'selected' => array(), 'bare' => true, 'empty_text' => __('No products associated.', 'ai-eshop-optimizer'), )); echo AIEO_Kit::row(__('Products', 'ai-eshop-optimizer'), $event_picker, __('Optional — specific products associated with this event (to monitor their pull).', 'ai-eshop-optimizer'), array('id' => 'aieo-event-products', 'group' => true)); } echo '
'; echo \Rooster\Admin\Ui::fold(__('Associated brands / categories / products', 'ai-eshop-optimizer'), (string) ob_get_clean()); echo '
'; if (class_exists('AIEO_Event_CPT') && method_exists('AIEO_Event_CPT', 'gf_form_options')) { echo AIEO_Kit::row(__('Self-registration form', 'ai-eshop-optimizer'), AIEO_Kit::select('aieo-event-gf', AIEO_Event_CPT::gf_form_options(0), '0', array('id' => 'aieo-event-gf')), __('Optional — a Gravity Form guests can use to register themselves (the self-registration front-end is added in a later phase).', 'ai-eshop-optimizer'), array('id' => 'aieo-event-gf')); } echo AIEO_Kit::row(__('Invitation subject', 'ai-eshop-optimizer'), \Rooster\Admin\Ui::input('', '', array('id' => 'aieo-event-invite-subject', 'medium' => true, 'placeholder' => __('e.g. You’re invited — Spring Brand Showcase', 'ai-eshop-optimizer'))), '', array('id' => 'aieo-event-invite-subject')); ob_start(); echo '
' . AIEO_Kit::button(__('Add Media', 'ai-eshop-optimizer'), array('size' => 'sm', 'icon' => 'image', 'class' => 'aieo-event-insert-media', 'attrs' => array('data-editor' => 'aieoeventinvitebody', 'aria-haspopup' => 'dialog'))) . '
'; wp_editor('', 'aieoeventinvitebody', array( 'textarea_name' => 'invite_body', 'textarea_rows' => 8, 'media_buttons' => false, 'teeny' => false, 'tinymce' => true, 'quicktags' => true, )); echo AIEO_Kit::row(__('Invitation body', 'ai-eshop-optimizer'), (string) ob_get_clean(), __('The invitation email content (sent to your guest list in a later phase). Rich text and images are supported.', 'ai-eshop-optimizer'), array('id' => 'aieoeventinvitebody')); $cur_sym = function_exists('get_woocommerce_currency_symbol') ? get_woocommerce_currency_symbol() : ''; $cur_code = function_exists('get_woocommerce_currency') ? get_woocommerce_currency() : ''; $event_row = \Rooster\Admin\Fields::compound( array( array('label' => trim(sprintf(__('Fee %s', 'ai-eshop-optimizer'), $cur_sym !== '' ? '(' . $cur_sym . ')' : '')), 'id' => 'aieo-event-fee', 'control' => \Rooster\Admin\Ui::input('', '', array('id' => 'aieo-event-fee', 'type' => 'number', 'short' => true, 'min' => 0, 'step' => 'any'))), array('label' => __('Currency', 'ai-eshop-optimizer'), 'id' => 'aieo-event-currency', 'control' => \Rooster\Admin\Ui::input('', (string) $cur_code, array('id' => 'aieo-event-currency', 'xs' => true, 'maxlength' => 3, 'class' => 'aieo-event-currency'))), ), array('label' => __('Admission fee', 'ai-eshop-optimizer')) ); echo AIEO_Kit::row(__('Admission fee', 'ai-eshop-optimizer'), $event_row, __('Optional admission price. Not charged yet — recorded for a future paid-events phase.', 'ai-eshop-optimizer'), array('id' => 'aieo-event-fee-group', 'group' => true)); echo '
'; echo '
'; echo $close; $events = get_posts(array( 'post_type' => AIEO_Event_CPT::POST_TYPE, 'post_status' => array('publish', 'draft', 'pending', 'future'), 'numberposts' => 200, 'orderby' => 'date', 'order' => 'DESC', )); list($open, $close) = AIEO_DMM_UI::card(array( 'anchor' => 'events-your-events', 'icon' => 'list', 'title' => __('Your events', 'ai-eshop-optimizer'), 'description' => __('Every event you have created, with its status, schedule and participants; edit, view or duplicate one.', 'ai-eshop-optimizer'), 'col' => 2, 'flush' => true, )); echo $open; if (empty($events)) { echo \Rooster\Admin\States::state('first-use', array('title' => __('No events yet — create one above.', 'ai-eshop-optimizer'))); } else { $sstate_labels = array('before' => __('upcoming', 'ai-eshop-optimizer'), 'live' => __('live', 'ai-eshop-optimizer'), 'ended' => __('ended', 'ai-eshop-optimizer')); $ev_rows = array(); foreach ($events as $e) { $edit = get_edit_post_link($e->ID); $view = get_permalink($e->ID); $ev_name = get_the_title($e) ?: __('(untitled)', 'ai-eshop-optimizer'); $sstate = method_exists('AIEO_Event_CPT', 'schedule_state') ? AIEO_Event_CPT::schedule_state($e->ID) : 'live'; $start_disp = AIEO_Event_CPT::fmt_dt(get_post_meta($e->ID, AIEO_Event_CPT::META_START, true)); $end_disp = AIEO_Event_CPT::fmt_dt(get_post_meta($e->ID, AIEO_Event_CPT::META_END, true)); if ($start_disp === '' && $end_disp === '') { $sched_html = esc_html__('Always open', 'ai-eshop-optimizer'); } else { $sched_html = esc_html__('Starts', 'ai-eshop-optimizer') . ': ' . esc_html($start_disp !== '' ? $start_disp : '—') . '
' . esc_html__('Ends', 'ai-eshop-optimizer') . ': ' . esc_html($end_disp !== '' ? $end_disp : '—'); } $c = class_exists('AIEO_Event_Participants') ? AIEO_Event_Participants::counts($e->ID) : array('invited' => 0, 'confirmed' => 0, 'declined' => 0, 'total' => 0); $manage = self::tab_url(array('manage' => $e->ID)); $acts = array( array('label' => __('Edit', 'ai-eshop-optimizer'), 'url' => $edit), array('label' => __('View', 'ai-eshop-optimizer'), 'url' => $view, 'attrs' => array('target' => '_blank', 'rel' => 'noopener')), ); if (class_exists('AIEO_Post_Duplicator')) { $acts[] = array('label' => __('Duplicate', 'ai-eshop-optimizer'), 'url' => AIEO_Post_Duplicator::url($e->ID)); } $ev_rows[] = array( '_id' => (int) $e->ID, '_name' => $ev_name, 'name' => array('title' => $ev_name, 'url' => $edit), 'status' => array('label' => get_post_status($e) . ' · ' . (isset($sstate_labels[$sstate]) ? $sstate_labels[$sstate] : $sstate), 'tone' => 'mono'), 'schedule' => array('html' => $sched_html), 'participants' => array('html' => (int) $c['total'] . ' (' . (int) $c['confirmed'] . ' ' . esc_html__('confirmed', 'ai-eshop-optimizer') . ', ' . (int) $c['invited'] . ' ' . esc_html__('invited', 'ai-eshop-optimizer') . ((int) $c['declined'] > 0 ? ', ' . (int) $c['declined'] . ' ' . esc_html__('declined', 'ai-eshop-optimizer') : '') . ')
' . esc_html__('Manage participants →', 'ai-eshop-optimizer') . ''), 'page' => $acts, ); } echo \Rooster\Admin\Ui::table( array( array('key' => 'name', 'label' => __('Name', 'ai-eshop-optimizer'), 'type' => 'text'), array('key' => 'status', 'label' => __('Status', 'ai-eshop-optimizer'), 'type' => 'status'), array('key' => 'schedule', 'label' => __('Schedule', 'ai-eshop-optimizer'), 'type' => 'html'), array('key' => 'participants', 'label' => __('Participants', 'ai-eshop-optimizer'), 'type' => 'html'), array('key' => 'page', 'label' => __('Page', 'ai-eshop-optimizer'), 'type' => 'actions'), ), $ev_rows, array('id' => 'aieo-events-list', 'caption' => esc_html__('Your events', 'ai-eshop-optimizer')) ); } echo $close; $eset = self::get_settings(); $msg_soon = isset($eset['msg_soon']) ? (string) $eset['msg_soon'] : ''; $msg_ended = isset($eset['msg_ended']) ? (string) $eset['msg_ended'] : ''; $msg_form = 'aieo-card-events-page-messages-form'; list($open, $close) = AIEO_DMM_UI::card(array( 'anchor' => 'events-page-messages', 'icon' => 'message-square-text', 'title' => __('Before and after event messages', 'ai-eshop-optimizer'), 'description' => __('Shown on the event page to visitors. These apply to ALL events. Leave a field empty to use the built-in (translatable) default.', 'ai-eshop-optimizer'), 'col' => 2, 'footer' => class_exists('\Rooster\Admin\States') ? \Rooster\Admin\States::save_button($msg_form) : '', )); echo $open; ob_start(); echo '
'; echo AIEO_Kit::row(__('“Coming soon” message', 'ai-eshop-optimizer'), AIEO_Kit::textarea('msg_soon', $msg_soon, array('id' => 'aieo-event-msg-soon', 'rows' => 2)), __('Shown before an event starts. Use %s where the start date should appear (optional).', 'ai-eshop-optimizer'), array('id' => 'aieo-event-msg-soon')); echo AIEO_Kit::row(__('“Ended” message', 'ai-eshop-optimizer'), AIEO_Kit::textarea('msg_ended', $msg_ended, array('id' => 'aieo-event-msg-ended', 'rows' => 2)), __('Shown after an event ends.', 'ai-eshop-optimizer'), array('id' => 'aieo-event-msg-ended')); echo '
'; echo AIEO_DMM_UI::card_form('aieo_events_settings_save', $this->get_id() . '_messages', $msg_form, (string) ob_get_clean(), array('nonce' => wp_create_nonce(self::NONCE), 'nonce_name' => 'nonce')); echo $close; rooster_admin_band_close(); } public function ajax_save_settings() { if (!check_ajax_referer(self::NONCE, 'nonce', false)) { wp_send_json_error(array('message' => __('Security check failed.', 'ai-eshop-optimizer'))); } if (!current_user_can('edit_posts')) { wp_send_json_error(array('message' => __('You are not allowed to do this.', 'ai-eshop-optimizer'))); } $ended = isset($_POST['msg_ended']) ? sanitize_textarea_field(wp_unslash($_POST['msg_ended'])) : ''; $soon = isset($_POST['msg_soon']) ? sanitize_textarea_field(wp_unslash($_POST['msg_soon'])) : ''; $settings = self::get_settings(); $settings['msg_soon'] = $soon; $settings['msg_ended'] = $ended; update_option(self::SETTINGS_OPTION, $settings, false); wp_send_json_success(array('saved' => true)); } private function image_field($which, $label) { $id = 'aieo-event-image-' . $which; return '
' . '' . esc_html($label) . '' . '' . '' . '' . AIEO_Kit::button(__('Select image', 'ai-eshop-optimizer'), array('class' => 'aieo-event-image-select')) . AIEO_Kit::button(__('Remove', 'ai-eshop-optimizer'), array('variant' => 'ghost', 'size' => 'sm', 'class' => 'aieo-event-image-remove', 'attrs' => array('hidden' => true))) . '
'; } public function ajax_save() { if (!check_ajax_referer(self::NONCE, 'nonce', false)) { wp_send_json_error(array('message' => __('Security check failed.', 'ai-eshop-optimizer'))); } if (!current_user_can('edit_posts')) { wp_send_json_error(array('message' => __('You are not allowed to do this.', 'ai-eshop-optimizer'))); } if (!class_exists('AIEO_Event_CPT')) { wp_send_json_error(array('message' => __('Events are unavailable.', 'ai-eshop-optimizer'))); } $post_id = isset($_POST['post_id']) ? (int) $_POST['post_id'] : 0; $name = isset($_POST['name']) ? sanitize_text_field(wp_unslash($_POST['name'])) : ''; if ($name === '') { wp_send_json_error(array('message' => __('Please enter an event name.', 'ai-eshop-optimizer'))); } $location = isset($_POST['location']) ? sanitize_text_field(wp_unslash($_POST['location'])) : ''; $desc = isset($_POST['short_desc']) ? sanitize_textarea_field(wp_unslash($_POST['short_desc'])) : ''; $img_d = isset($_POST['img_desktop']) ? (int) $_POST['img_desktop'] : 0; $img_m = isset($_POST['img_mobile']) ? (int) $_POST['img_mobile'] : 0; $start = isset($_POST['start']) ? sanitize_text_field(wp_unslash($_POST['start'])) : ''; $end = isset($_POST['end']) ? sanitize_text_field(wp_unslash($_POST['end'])) : ''; $rsvp_deadline = isset($_POST['rsvp_deadline']) ? sanitize_text_field(wp_unslash($_POST['rsvp_deadline'])) : ''; $gf = isset($_POST['gf_id']) ? (int) $_POST['gf_id'] : 0; $invite_subject = isset($_POST['invite_subject']) ? sanitize_text_field(wp_unslash($_POST['invite_subject'])) : ''; $invite_body = isset($_POST['invite_body']) ? wp_kses_post(wp_unslash($_POST['invite_body'])) : ''; $fee = isset($_POST['fee']) ? (float) $_POST['fee'] : 0; $currency = isset($_POST['currency']) ? strtoupper(sanitize_text_field(wp_unslash($_POST['currency']))) : ''; $brands = isset($_POST['brands']) ? array_map('intval', (array) wp_unslash($_POST['brands'])) : array(); $categories = isset($_POST['categories']) ? array_map('intval', (array) wp_unslash($_POST['categories'])) : array(); $products = class_exists('AIEO_DMM_Product_Picker') ? AIEO_DMM_Product_Picker::roll_up_to_parents(AIEO_DMM_Product_Picker::collect_ids('event_products')) : (isset($_POST['event_products']) ? array_map('intval', (array) wp_unslash($_POST['event_products'])) : array()); $args = array( 'post_type' => AIEO_Event_CPT::POST_TYPE, 'post_title' => $name, 'post_status' => 'publish', ); if ($post_id > 0) { $args['ID'] = $post_id; $res = wp_update_post($args, true); } else { $res = wp_insert_post($args, true); } if (is_wp_error($res)) { wp_send_json_error(array('message' => $res->get_error_message())); } $post_id = (int) $res; AIEO_Event_CPT::persist_fields( $post_id, $gf, $desc, $location, $img_d, $img_m, $start, $end, $rsvp_deadline, $brands, $categories, $products, $fee, $currency ); update_post_meta($post_id, AIEO_Event_CPT::META_INVITE_SUBJECT, $invite_subject); update_post_meta($post_id, AIEO_Event_CPT::META_INVITE_BODY, $invite_body); $map_url = isset($_POST['map_url']) ? esc_url_raw(wp_unslash($_POST['map_url'])) : ''; update_post_meta($post_id, AIEO_Event_CPT::META_MAP_URL, $map_url); wp_send_json_success(array( 'post_id' => $post_id, 'title' => get_the_title($post_id), 'edit_url' => get_edit_post_link($post_id, 'raw'), 'view_url' => get_permalink($post_id), 'status' => get_post_status($post_id), )); } private static function stash_result($data) { set_transient('aieo_events_import_' . get_current_user_id(), $data, 60); } private static function pull_result() { $k = 'aieo_events_import_' . get_current_user_id(); $d = get_transient($k); if ($d !== false) { delete_transient($k); } return is_array($d) ? $d : null; } private function render_manage_screen($event_id) { $event_id = (int) $event_id; $title = get_the_title($event_id); list($open, $close) = AIEO_DMM_UI::card(array( 'anchor' => 'events-guests-summary', 'icon' => 'users', 'title' => sprintf(__('Participants — %s', 'ai-eshop-optimizer'), $title !== '' ? $title : __('(untitled)', 'ai-eshop-optimizer')), 'span' => 'all', )); echo $open; echo '

← ' . esc_html__('Back to events', 'ai-eshop-optimizer') . '

'; $res = self::pull_result(); if ($res) { if (!empty($res['error'])) { echo AIEO_DMM_UI::notice(esc_html((string) $res['error']), 'destructive'); } elseif (!empty($res['notice'])) { echo AIEO_DMM_UI::notice(esc_html((string) $res['notice']), 'success'); } else { $mode_label = (isset($res['mode']) && $res['mode'] === 'overwrite') ? __('Overwrite', 'ai-eshop-optimizer') : __('Update', 'ai-eshop-optimizer'); $line = sprintf( __('%1$s complete — %2$d rows read: %3$d added, %4$d updated, %5$d removed, %6$d skipped.', 'ai-eshop-optimizer'), $mode_label, (int) ($res['total'] ?? 0), (int) ($res['inserted'] ?? 0), (int) ($res['updated'] ?? 0), (int) ($res['removed'] ?? 0), (int) ($res['skipped'] ?? 0) ); $detail = ''; if (!empty($res['errors']) && is_array($res['errors'])) { $shown = array_slice($res['errors'], 0, 12); $detail .= ''; } echo AIEO_DMM_UI::notice(esc_html($line), !empty($res['errors']) ? 'warning' : 'success', array('detail' => $detail)); } } $st = class_exists('AIEO_Event_Participants') ? AIEO_Event_Participants::stats($event_id) : array('total' => 0, 'confirmed' => 0, 'declined' => 0, 'invited' => 0, 'responded' => 0, 'response_rate' => 0, 'imported' => 0, 'self_registered' => 0, 'invited_sent' => 0); $chip = static function ($label, $value, $color, $suffix = '') { return '' . esc_html((string) $value . $suffix) . ' ' . esc_html($label) . ''; }; echo '
'; echo $chip(__('total', 'ai-eshop-optimizer'), (int) $st['total'], 'mono'); echo $chip(__('confirmed', 'ai-eshop-optimizer'), (int) $st['confirmed'], 'success'); echo $chip(__('declined', 'ai-eshop-optimizer'), (int) $st['declined'], 'destructive'); echo $chip(__('awaiting reply', 'ai-eshop-optimizer'), (int) $st['invited'], 'warning'); echo $chip(__('response rate', 'ai-eshop-optimizer'), (int) $st['response_rate'], 'info', '%'); echo '
'; echo '

' . esc_html(sprintf(__('%1$d imported · %2$d self-registered · %3$d invitation(s) sent', 'ai-eshop-optimizer'), (int) $st['imported'], (int) $st['self_registered'], (int) $st['invited_sent'])) . '

'; echo $close; list($open, $close) = AIEO_DMM_UI::card(array( 'anchor' => 'events-guests-import', 'icon' => 'upload', 'title' => __('Import participants', 'ai-eshop-optimizer'), 'col' => 1, 'footer' => AIEO_Kit::button(__('Upload and import', 'ai-eshop-optimizer'), array('variant' => 'primary', 'type' => 'submit', 'attrs' => array('form' => 'aieo-event-import-form'))), )); echo $open; echo '
'; echo ''; echo ''; wp_nonce_field('aieo_events_import'); echo '

'; echo '
'; echo ''; echo ''; echo '
'; echo '

' . esc_html__('Accepted: .xlsx or .csv with a header row. Recognised columns (in your own language or English, any order): Salutation, Title, Name, Surname, Department, Organization, Email (required), Phone.', 'ai-eshop-optimizer') . '

'; echo '
'; echo $close; $this->render_invites_card($event_id); list($open, $close) = AIEO_DMM_UI::card(array( 'anchor' => 'events-guests-self-registration', 'icon' => 'user-plus', 'title' => __('Self-registration', 'ai-eshop-optimizer'), 'col' => 2, )); echo $open; echo '

' . esc_html__('Let guests sign themselves up: add the Rooster One “Event Registration” block to this event’s page, or paste the shortcode below into its content. Self-registrations appear in the guest list tagged “Self-registered”.', 'ai-eshop-optimizer') . '

'; echo '

[aieo_event_register]'; $ev_edit = get_edit_post_link($event_id); if ($ev_edit) { echo ' · ' . esc_html__('Edit event →', 'ai-eshop-optimizer') . ''; } echo '

'; echo $close; $search = isset($_GET['psearch']) ? sanitize_text_field(wp_unslash($_GET['psearch'])) : ''; $per = 50; $page = max(1, isset($_GET['ppage']) ? (int) $_GET['ppage'] : 1); $total = class_exists('AIEO_Event_Participants') ? AIEO_Event_Participants::count_for_event($event_id, array('search' => $search)) : 0; $rows = class_exists('AIEO_Event_Participants') ? AIEO_Event_Participants::get_for_event($event_id, array( 'search' => $search, 'orderby' => 'last_name', 'order' => 'ASC', 'limit' => $per, 'offset' => ($page - 1) * $per, )) : array(); $export = ''; if ((int) $st['total'] > 0 && current_user_can(self::export_capability())) { $export_url = wp_nonce_url(admin_url('admin-post.php?action=aieo_events_export&event_id=' . $event_id), 'aieo_events_export'); $export = AIEO_Kit::button(__('Export to XLSX', 'ai-eshop-optimizer'), array('size' => 'sm', 'href' => $export_url)); } list($open, $close) = AIEO_DMM_UI::card(array( 'anchor' => 'events-guests-list', 'icon' => 'list', 'title' => __('Guest list', 'ai-eshop-optimizer'), 'tools' => $export, 'span' => 'all', 'flush' => true, )); echo $open; echo '
'; echo ''; echo ''; echo ''; echo \Rooster\Admin\Ui::filter(__('Search', 'ai-eshop-optimizer'), \Rooster\Admin\Ui::input('psearch', $search, array('type' => 'search', 'id' => 'aieo-event-psearch', 'medium' => true, 'placeholder' => __('Search name, email, organization…', 'ai-eshop-optimizer'))), 'aieo-event-psearch'); echo '
' . AIEO_Kit::button(__('Search', 'ai-eshop-optimizer'), array('type' => 'submit')) . ($search !== '' ? AIEO_Kit::button(__('Clear', 'ai-eshop-optimizer'), array('variant' => 'ghost', 'href' => self::tab_url(array('manage' => $event_id)))) : '') . '
'; echo '
'; if (empty($rows)) { echo '

' . esc_html($search !== '' ? __('No matching participants.', 'ai-eshop-optimizer') : __('No participants yet — import a list above.', 'ai-eshop-optimizer')) . '

'; } else { $src_labels = array('imported' => __('Imported', 'ai-eshop-optimizer'), 'self-registered' => __('Self-registered', 'ai-eshop-optimizer')); $rs_labels = array('invited' => __('Invited', 'ai-eshop-optimizer'), 'confirmed' => __('Confirmed', 'ai-eshop-optimizer'), 'declined' => __('Declined', 'ai-eshop-optimizer')); $ep_rows = array(); if (!class_exists('AIEO_Submission_Panel', false) && is_readable(AIEO_DIR . 'includes/dmm/class-aieo-submission-panel.php')) { require_once AIEO_DIR . 'includes/dmm/class-aieo-submission-panel.php'; } $ep_leads = class_exists('AIEO_Submission_Panel') ? AIEO_Submission_Panel::keys_for('event', array_map(static function ($r) { return (int) $r->participant_id; }, (array) $rows)) : array(); foreach ($rows as $row) { $pid = (int) $row->participant_id; $del = wp_nonce_url( admin_url('admin-post.php?action=aieo_events_participant_delete&event_id=' . $event_id . '&pid=' . $pid), 'aieo_events_pdel_' . $pid ); $src = isset($src_labels[$row->source]) ? $src_labels[$row->source] : $row->source; $rs = isset($rs_labels[$row->rsvp_status]) ? $rs_labels[$row->rsvp_status] : $row->rsvp_status; $rsvp_url = class_exists('AIEO_Event_RSVP') ? AIEO_Event_RSVP::url($row->rsvp_token) : ''; $acts = array(); if ($rsvp_url !== '') { $acts[] = array( 'label' => __('RSVP', 'ai-eshop-optimizer'), 'url' => $rsvp_url, 'attrs' => array('target' => '_blank', 'rel' => 'noopener', 'title' => __('Open this guest’s RSVP page', 'ai-eshop-optimizer')), ); } if (isset($ep_leads[$pid])) { $acts[] = array( 'label' => __('Campaign and journey', 'ai-eshop-optimizer'), 'url' => AIEO_Submission_Panel::url($ep_leads[$pid]), ); } $acts[] = array( 'label' => __('Remove', 'ai-eshop-optimizer'), 'url' => $del, 'destructive' => true, 'attrs' => \Rooster\Admin\States::confirm_attrs('aieo-event-remove-dialog'), ); $ep_rows[] = array( '_id' => $pid, '_name' => trim($row->first_name . ' ' . $row->last_name), 'salutation' => (string) $row->salutation, 'title' => (string) $row->title, 'first_name' => (string) $row->first_name, 'last_name' => (string) $row->last_name, 'organization' => (string) $row->organization, 'department' => (string) $row->department, 'email' => (string) $row->email, 'phone' => (string) $row->phone, 'source' => (string) $src, 'rsvp' => (string) $rs, 'actions' => $acts, ); } $ep_cols = array(); foreach (array( 'salutation' => __('Salutation', 'ai-eshop-optimizer'), 'title' => __('Title', 'ai-eshop-optimizer'), 'first_name' => __('Name', 'ai-eshop-optimizer'), 'last_name' => __('Surname', 'ai-eshop-optimizer'), 'organization' => __('Organization', 'ai-eshop-optimizer'), 'department' => __('Department', 'ai-eshop-optimizer'), 'email' => __('Email', 'ai-eshop-optimizer'), 'phone' => __('Phone', 'ai-eshop-optimizer'), 'source' => __('Source', 'ai-eshop-optimizer'), 'rsvp' => __('RSVP', 'ai-eshop-optimizer'), ) as $ep_key => $ep_label) { $ep_cols[] = array('key' => $ep_key, 'label' => $ep_label, 'type' => 'text'); } $ep_cols[] = array('key' => 'actions', 'label' => __('Actions', 'ai-eshop-optimizer'), 'type' => 'actions'); $ep_pages = (int) ceil($total / $per); echo \Rooster\Admin\Ui::table( $ep_cols, $ep_rows, array( 'id' => 'aieo-events-participants', 'caption' => esc_html__('Guest list', 'ai-eshop-optimizer'), 'scroll' => true, 'footer' => $ep_pages > 1 ? \Rooster\Admin\Ui::pager( $page, $ep_pages, static function ($n) use ($event_id, $search) { return self::tab_url(array('manage' => $event_id, 'psearch' => $search, 'ppage' => $n)); }, array('total' => (int) $total) ) : '', ) ); echo '

' . esc_html(sprintf(__('Showing %1$d of %2$d participants.', 'ai-eshop-optimizer'), count($rows), (int) $total)) . '

'; echo \Rooster\Admin\States::confirm('aieo-event-remove-dialog', 'delete', __('Remove this participant?', 'ai-eshop-optimizer'), '', array('confirm' => __('Remove', 'ai-eshop-optimizer'))); } echo $close; } public function handle_import() { if (!current_user_can('edit_posts')) { wp_die(esc_html__('You are not allowed to do this.', 'ai-eshop-optimizer')); } check_admin_referer('aieo_events_import'); $event_id = isset($_POST['event_id']) ? (int) $_POST['event_id'] : 0; $mode = (isset($_POST['mode']) && $_POST['mode'] === 'overwrite') ? 'overwrite' : 'update'; if ($event_id <= 0 || !class_exists('AIEO_Event_CPT') || get_post_type($event_id) !== AIEO_Event_CPT::POST_TYPE) { self::stash_result(array('error' => __('Invalid event.', 'ai-eshop-optimizer'))); wp_safe_redirect(self::tab_url()); exit; } $redirect = self::tab_url(array('manage' => $event_id)); if (empty($_FILES['participants_file']) || !isset($_FILES['participants_file']['error']) || (int) $_FILES['participants_file']['error'] !== UPLOAD_ERR_OK) { self::stash_result(array('error' => __('No file was uploaded, or the upload failed.', 'ai-eshop-optimizer'))); wp_safe_redirect($redirect); exit; } $file = $_FILES['participants_file']; if (empty($file['tmp_name']) || !is_uploaded_file($file['tmp_name'])) { self::stash_result(array('error' => __('The upload could not be verified.', 'ai-eshop-optimizer'))); wp_safe_redirect($redirect); exit; } $size = isset($file['size']) ? (int) $file['size'] : 0; if ($size <= 0 || $size > 12 * 1024 * 1024) { self::stash_result(array('error' => __('The file is empty or larger than 12 MB.', 'ai-eshop-optimizer'))); wp_safe_redirect($redirect); exit; } $ext = strtolower(pathinfo(isset($file['name']) ? (string) $file['name'] : '', PATHINFO_EXTENSION)); if (!in_array($ext, array('xlsx', 'csv'), true)) { self::stash_result(array('error' => __('Unsupported file type. Upload a .xlsx or .csv file.', 'ai-eshop-optimizer'))); wp_safe_redirect($redirect); exit; } if (!class_exists('AIEO_Event_Importer') && defined('AIEO_DIR') && file_exists(AIEO_DIR . 'includes/dmm/events/class-aieo-event-importer.php')) { require_once AIEO_DIR . 'includes/dmm/events/class-aieo-event-importer.php'; } if (!class_exists('AIEO_Event_Importer')) { self::stash_result(array('error' => __('The importer is unavailable.', 'ai-eshop-optimizer'))); wp_safe_redirect($redirect); exit; } $parsed = AIEO_Event_Importer::parse_file($file['tmp_name'], $ext); if (is_wp_error($parsed)) { self::stash_result(array('error' => $parsed->get_error_message())); wp_safe_redirect($redirect); exit; } $summary = AIEO_Event_Importer::run_import($event_id, $parsed, $mode, get_current_user_id()); $summary['mode'] = $mode; self::stash_result($summary); wp_safe_redirect($redirect); exit; } public function handle_participant_delete() { if (!current_user_can('edit_posts')) { wp_die(esc_html__('You are not allowed to do this.', 'ai-eshop-optimizer')); } $event_id = isset($_GET['event_id']) ? (int) $_GET['event_id'] : 0; $pid = isset($_GET['pid']) ? (int) $_GET['pid'] : 0; check_admin_referer('aieo_events_pdel_' . $pid); if ($event_id > 0 && $pid > 0 && class_exists('AIEO_Event_Participants')) { global $wpdb; $wpdb->delete(AIEO_Event_Participants::table(), array('participant_id' => $pid, 'event_id' => $event_id), array('%d', '%d')); self::stash_result(array('notice' => __('Participant removed.', 'ai-eshop-optimizer'))); } wp_safe_redirect(self::tab_url(array('manage' => $event_id))); exit; } private function render_invites_card($event_id) { $event_id = (int) $event_id; if (!class_exists('AIEO_Event_Invites') && defined('AIEO_DIR') && file_exists(AIEO_DIR . 'includes/dmm/events/class-aieo-event-invites.php')) { require_once AIEO_DIR . 'includes/dmm/events/class-aieo-event-invites.php'; } $subject = (string) get_post_meta($event_id, AIEO_Event_CPT::META_INVITE_SUBJECT, true); $body = (string) get_post_meta($event_id, AIEO_Event_CPT::META_INVITE_BODY, true); $aieo_ev_ready = !($subject === '' || $body === '' || !class_exists('AIEO_Event_Invites')); $aieo_ev_live = !empty(self::get_settings()['live_send']); list($open, $close) = AIEO_DMM_UI::card(array( 'anchor' => 'events-guests-invitations', 'icon' => 'mail', 'title' => __('Invitations', 'ai-eshop-optimizer'), 'col' => 2, 'footer' => $aieo_ev_ready ? AIEO_Kit::button($aieo_ev_live ? __('Send invitations', 'ai-eshop-optimizer') : __('Dry run (no emails sent)', 'ai-eshop-optimizer'), array('variant' => 'primary', 'type' => 'submit', 'attrs' => array('form' => 'aieo-event-send-form') + ($aieo_ev_live ? \Rooster\Admin\States::confirm_attrs('aieo-event-send-dialog') : array()))) : '', )); echo $open; if ($subject === '' || $body === '' || !class_exists('AIEO_Event_Invites')) { echo '

' . esc_html__('Set the invitation subject and body on the event’s edit screen, then return here to preview and send.', 'ai-eshop-optimizer') . ' '; $edit = get_edit_post_link($event_id); if ($edit) { echo '' . esc_html__('Edit event →', 'ai-eshop-optimizer') . ''; } echo '

'; echo $close; return; } echo '

' . esc_html__('Merge tags for the subject and body:', 'ai-eshop-optimizer') . ' {salutation} {title} {name} {first_name} {last_name} {organization} {department} {event_title} {event_date} {event_location} {event_map_link} {event_map_url} {rsvp_link} {rsvp_url}. ' . esc_html__('If you don’t place an RSVP tag, an RSVP button is appended automatically.', 'ai-eshop-optimizer') . '

'; $settings = self::get_settings(); $live = !empty($settings['live_send']); ob_start(); echo '
'; echo ''; echo ''; wp_nonce_field('aieo_events_invites_settings'); echo ''; echo '' . ($live ? esc_html__('Live sending is ON — Send delivers real emails.', 'ai-eshop-optimizer') : esc_html__('Live sending is OFF — Send runs a dry run (no emails sent).', 'ai-eshop-optimizer')) . ''; echo '
'; $live_form = (string) ob_get_clean(); $counts = AIEO_Event_Invites::scope_counts($event_id); echo '
'; echo ''; echo ''; wp_nonce_field('aieo_events_invites'); echo '
'; echo ''; echo ''; echo ''; echo '
'; echo '
'; if ($live) { echo \Rooster\Admin\States::confirm('aieo-event-send-dialog', 'apply', __('Send invitations now? Real emails will be delivered.', 'ai-eshop-optimizer'), '', array('confirm' => __('Send invitations', 'ai-eshop-optimizer'))); } $sample = AIEO_Event_Invites::sample(get_post($event_id)); echo rooster_admin_card_section_html(__('Preview', 'ai-eshop-optimizer')); echo '

' . esc_html__('Subject', 'ai-eshop-optimizer') . ': ' . esc_html($sample['subject']) . '

'; echo ''; echo $close; list($open, $close) = AIEO_DMM_UI::card(array( 'anchor' => 'events-guests-live-sending', 'icon' => 'send', 'title' => __('Live sending', 'ai-eshop-optimizer'), 'col' => 2, 'footer' => AIEO_Kit::button(__('Save', 'ai-eshop-optimizer'), array('type' => 'submit', 'attrs' => array('form' => 'aieo-event-live-form'))), )); echo $open . $live_form . $close; } public function handle_invites_send() { if (!current_user_can('edit_posts')) { wp_die(esc_html__('You are not allowed to do this.', 'ai-eshop-optimizer')); } check_admin_referer('aieo_events_invites'); $event_id = isset($_POST['event_id']) ? (int) $_POST['event_id'] : 0; $scope = (isset($_POST['scope']) && in_array($_POST['scope'], array('all', 'new', 'pending'), true)) ? sanitize_key(wp_unslash($_POST['scope'])) : 'pending'; if ($event_id <= 0 || !class_exists('AIEO_Event_CPT') || get_post_type($event_id) !== AIEO_Event_CPT::POST_TYPE) { self::stash_result(array('error' => __('Invalid event.', 'ai-eshop-optimizer'))); wp_safe_redirect(self::tab_url()); exit; } $redirect = self::tab_url(array('manage' => $event_id)); if (!class_exists('AIEO_Event_Invites') && defined('AIEO_DIR') && file_exists(AIEO_DIR . 'includes/dmm/events/class-aieo-event-invites.php')) { require_once AIEO_DIR . 'includes/dmm/events/class-aieo-event-invites.php'; } if (!class_exists('AIEO_Event_Invites')) { self::stash_result(array('error' => __('The invitation sender is unavailable.', 'ai-eshop-optimizer'))); wp_safe_redirect($redirect); exit; } $settings = self::get_settings(); $live = !empty($settings['live_send']); $res = AIEO_Event_Invites::run($event_id, $scope, $live); if (isset($res['error']) && $res['error'] === 'no_template') { self::stash_result(array('error' => __('Set the invitation subject and body on the event’s edit screen first.', 'ai-eshop-optimizer'))); } elseif (!$live) { self::stash_result(array('notice' => sprintf( __('Dry run — %1$d recipient(s) in scope “%2$s”. No emails were sent. Enable live sending above to send for real.', 'ai-eshop-optimizer'), (int) $res['recipients'], $scope ))); } else { self::stash_result(array('notice' => sprintf( __('Invitations: %1$d sent, %2$d failed, %3$d skipped (of %4$d).', 'ai-eshop-optimizer'), (int) $res['sent'], (int) $res['failed'], (int) $res['skipped'], (int) $res['recipients'] ))); } wp_safe_redirect($redirect); exit; } public function handle_invites_settings() { if (!current_user_can('edit_posts')) { wp_die(esc_html__('You are not allowed to do this.', 'ai-eshop-optimizer')); } check_admin_referer('aieo_events_invites_settings'); $event_id = isset($_POST['event_id']) ? (int) $_POST['event_id'] : 0; $settings = self::get_settings(); $settings['live_send'] = !empty($_POST['live_send']); update_option(self::SETTINGS_OPTION, $settings, false); self::stash_result(array('notice' => $settings['live_send'] ? __('Live sending enabled.', 'ai-eshop-optimizer') : __('Live sending disabled (dry-run only).', 'ai-eshop-optimizer'))); wp_safe_redirect($event_id > 0 ? self::tab_url(array('manage' => $event_id)) : self::tab_url()); exit; } private static function export_capability() { return class_exists('AIEO_Report_Roles') ? AIEO_Report_Roles::capability_for('export') : 'manage_options'; } public function handle_export() { if (!current_user_can(self::export_capability())) { wp_die(esc_html__('You do not have permission to export this report.', 'ai-eshop-optimizer')); } check_admin_referer('aieo_events_export'); $event_id = isset($_GET['event_id']) ? (int) $_GET['event_id'] : 0; if ($event_id <= 0 || !class_exists('AIEO_Event_CPT') || get_post_type($event_id) !== AIEO_Event_CPT::POST_TYPE) { wp_die(esc_html__('Invalid event.', 'ai-eshop-optimizer')); } if (!class_exists('\Rooster\Admin\Export') && function_exists('rooster_admin_builders')) { rooster_admin_builders(); } if (!class_exists('\Rooster\Admin\Export') || !class_exists('AIEO_Event_Participants')) { wp_die(esc_html__('Export is unavailable.', 'ai-eshop-optimizer')); } $rows = AIEO_Event_Participants::get_for_event($event_id, array('orderby' => 'last_name', 'order' => 'ASC')); $fmt_dt = static function ($gmt) { $gmt = (string) $gmt; if ($gmt === '' || substr($gmt, 0, 4) === '0000') { return ''; } return get_date_from_gmt($gmt, 'Y-m-d H:i'); }; $src_labels = array('imported' => __('Imported', 'ai-eshop-optimizer'), 'self-registered' => __('Self-registered', 'ai-eshop-optimizer')); $rs_labels = array('invited' => __('Invited', 'ai-eshop-optimizer'), 'confirmed' => __('Confirmed', 'ai-eshop-optimizer'), 'declined' => __('Declined', 'ai-eshop-optimizer')); $columns = array(); foreach (array( 'salutation' => __('Salutation', 'ai-eshop-optimizer'), 'title' => __('Title', 'ai-eshop-optimizer'), 'first_name' => __('First name', 'ai-eshop-optimizer'), 'last_name' => __('Last name', 'ai-eshop-optimizer'), 'organization' => __('Organization', 'ai-eshop-optimizer'), 'department' => __('Department', 'ai-eshop-optimizer'), 'email' => __('Email', 'ai-eshop-optimizer'), 'phone' => __('Phone', 'ai-eshop-optimizer'), 'source' => __('Source', 'ai-eshop-optimizer'), 'rsvp' => __('RSVP status', 'ai-eshop-optimizer'), 'invited' => __('Invited at', 'ai-eshop-optimizer'), 'responded' => __('Responded at', 'ai-eshop-optimizer'), 'registered' => __('Registered at', 'ai-eshop-optimizer'), ) as $key => $label) { $columns[$key] = array('label' => $label, 'type' => 'text'); } $lines = static function () use ($rows, $src_labels, $rs_labels, $fmt_dt) { foreach ($rows as $r) { yield array( 'salutation' => (string) $r->salutation, 'title' => (string) $r->title, 'first_name' => (string) $r->first_name, 'last_name' => (string) $r->last_name, 'organization' => (string) $r->organization, 'department' => (string) $r->department, 'email' => (string) $r->email, 'phone' => (string) $r->phone, 'source' => isset($src_labels[$r->source]) ? $src_labels[$r->source] : (string) $r->source, 'rsvp' => isset($rs_labels[$r->rsvp_status]) ? $rs_labels[$r->rsvp_status] : (string) $r->rsvp_status, 'invited' => $fmt_dt($r->invited_at), 'responded' => $fmt_dt($r->responded_at), 'registered' => $fmt_dt($r->created_at), ); } }; $slug = sanitize_title(get_the_title($event_id)); \Rooster\Admin\Export::xlsx('participants-' . ($slug !== '' ? $slug : $event_id) . '.xlsx', array(array('name' => __('Participants', 'ai-eshop-optimizer'), 'columns' => $columns, 'rows' => $lines()))); exit; } }