'evqra_paypal_test_connection',
'nonce' => wp_create_nonce('evqra_paypal_test_connection'),
'mode' => strtoupper(get_option('evqra_paypal_mode', 'sandbox')),
'testingText' => __('Testing connection…', 'eventqora'),
'testText' => __('Test PayPal Connection', 'eventqora'),
'verifiedText' => __('Connection verified', 'eventqora'),
'failedText' => __('Connection failed', 'eventqora'),
'successText' => __('PayPal connection verified successfully.', 'eventqora'),
'failureText' => __('PayPal connection test failed.', 'eventqora'),
]) . ';', 'before');
}
}
public function render_settings_page() {
$tabs = [
'general' => ['label' => __('General', 'eventqora'), 'icon' => '⚙'],
'display' => ['label' => __('Display & Directories', 'eventqora'), 'icon' => '▦'],
'email' => ['label' => __('Email Notifications', 'eventqora'), 'icon' => '✉'],
'google_maps' => ['label' => __('Google Maps API', 'eventqora'), 'icon' => '⌖'],
'paypal' => ['label' => __('PayPal Settings', 'eventqora'), 'icon' => '◈'],
];
$current_tab = filter_input(INPUT_GET, 'tab', FILTER_SANITIZE_SPECIAL_CHARS) ? sanitize_key(wp_unslash(filter_input(INPUT_GET, 'tab', FILTER_SANITIZE_SPECIAL_CHARS))) : 'general';
if (!isset($tabs[$current_tab])) {
$current_tab = 'general';
}
echo '
';
echo '
';
echo '
' . esc_html__('EventQora', 'eventqora') . ' ';
echo '
' . esc_html__('Settings', 'eventqora') . ' ';
echo '
' . esc_html__('Configure your event calendar, frontend directories, notifications, maps, and payments from one place.', 'eventqora') . '
';
echo '
';
echo '
';
foreach ($tabs as $key => $tab) {
$url = add_query_arg([
'post_type' => 'evqra_event',
'page' => 'eventqora-settings',
'tab' => $key,
], admin_url('edit.php'));
$class = $current_tab === $key ? ' evqra-settings-tab--active' : '';
echo '';
echo '' . esc_html($tab['icon']) . ' ';
echo '' . esc_html($tab['label']) . ' ';
}
echo ' ';
echo '
';
settings_errors();
echo '
';
}
public function redirect_legacy_settings() {
if (!is_admin() || !current_user_can('manage_options')) {
return;
}
if (filter_input(INPUT_GET, 'page', FILTER_SANITIZE_SPECIAL_CHARS) && sanitize_key(wp_unslash(filter_input(INPUT_GET, 'page', FILTER_SANITIZE_SPECIAL_CHARS))) === 'evqra-event-settings') {
wp_safe_redirect(admin_url('edit.php?post_type=evqra_event&page=eventqora-settings'));
exit;
}
}
public function sanitize_date_format($value) { return sanitize_text_field($value); }
public function sanitize_timezone($value) { $value = sanitize_text_field($value); return in_array($value, timezone_identifiers_list(), true) ? $value : wp_timezone_string(); }
public function sanitize_default_view($value) { $value = sanitize_key($value); $legacy = ['month-view' => 'month', 'week-view' => 'week', 'day-view' => 'day', 'list-view' => 'list']; $value = $legacy[$value] ?? $value; $allowed = ['month', 'week', 'day', 'list', 'photo', 'map']; return in_array($value, $allowed, true) ? $value : 'month'; }
public function sanitize_calendar_time_format($value) { $value = sanitize_key($value); return in_array($value, ['wordpress', '24h', '12h'], true) ? $value : 'wordpress'; }
public function sanitize_calendar_enabled_views($value) {
$allowed = ['month', 'week', 'day', 'list', 'photo', 'map'];
$views = is_array($value) ? array_map('sanitize_key', $value) : [];
$views = array_values(array_intersect($allowed, $views));
return $views ? $views : ['month'];
}
public function sanitize_calendar_category_colors($value) {
$value = sanitize_key($value);
return in_array($value, ['line', 'background', 'off'], true) ? $value : 'background';
}
public function sanitize_events_per_page($value) { return max(1, min(200, absint($value))); }
public function sanitize_currency($value) { $value = strtoupper(sanitize_text_field($value)); $allowed = ['USD','EUR','GBP','INR','AUD','CAD','SGD','AED']; return in_array($value, $allowed, true) ? $value : 'USD'; }
public function sanitize_bool($value) { return !empty($value) ? 1 : 0; }
public function sanitize_google_maps_key($value) { return sanitize_text_field($value); }
public function sanitize_zoom($value) { return max(1, min(21, absint($value))); }
public function register_settings() {
// General Tab
register_setting('evqra_settings_general', 'evqra_date_format', ['type' => 'string', 'default' => 'Y-m-d', 'sanitize_callback' => [$this, 'sanitize_date_format']]);
register_setting('evqra_settings_general', 'evqra_timezone', ['type' => 'string', 'default' => wp_timezone_string(), 'sanitize_callback' => [$this, 'sanitize_timezone']]);
register_setting('evqra_settings_general', 'evqra_currency', ['type' => 'string', 'default' => 'USD', 'sanitize_callback' => [$this, 'sanitize_currency']]);
add_settings_section('evqra_general_section', '', null, 'evqra-settings-general');
add_settings_field('evqra_date_format', __('Date Format', 'eventqora'), [$this, 'render_text_input'], 'evqra-settings-general', 'evqra_general_section', [
'id' => 'evqra_date_format', 'desc' => __('Use PHP date format (e.g., Y-m-d, d/m/Y)', 'eventqora')
]);
add_settings_field('evqra_timezone', __('Time Zone', 'eventqora'), [$this, 'render_select_input'], 'evqra-settings-general', 'evqra_general_section', [
'id' => 'evqra_timezone', 'options' => timezone_identifiers_list()
]);
add_settings_field('evqra_currency', __('Currency', 'eventqora'), [$this, 'render_select_input'], 'evqra-settings-general', 'evqra_general_section', [
'id' => 'evqra_currency', 'options' => ['USD'=>'USD','EUR'=>'EUR','GBP'=>'GBP','INR'=>'INR','AUD'=>'AUD','CAD'=>'CAD','SGD'=>'SGD','AED'=>'AED']
]);
// Display & Directories Tab: calendar controls share the display settings form.
register_setting('evqra_settings_display', 'evqra_default_view', ['type' => 'string', 'default' => 'month', 'sanitize_callback' => [$this, 'sanitize_default_view']]);
register_setting('evqra_settings_display', 'evqra_events_per_page', ['type' => 'integer', 'default' => 10, 'sanitize_callback' => [$this, 'sanitize_events_per_page']]);
register_setting('evqra_settings_display', 'evqra_calendar_time_format', ['type' => 'string', 'default' => 'wordpress', 'sanitize_callback' => [$this, 'sanitize_calendar_time_format']]);
register_setting('evqra_settings_display', 'evqra_calendar_enabled_views', ['type' => 'array', 'default' => ['month', 'week', 'list', 'photo', 'map', 'day'], 'sanitize_callback' => [$this, 'sanitize_calendar_enabled_views']]);
register_setting('evqra_settings_display', 'evqra_calendar_show_filters', ['type' => 'boolean', 'default' => 1, 'sanitize_callback' => [$this, 'sanitize_bool']]);
register_setting('evqra_settings_display', 'evqra_calendar_category_colors', ['type' => 'string', 'default' => 'background', 'sanitize_callback' => [$this, 'sanitize_calendar_category_colors']]);
register_setting('evqra_settings_display', 'evqra_calendar_full_event_names', ['type' => 'boolean', 'default' => 0, 'sanitize_callback' => [$this, 'sanitize_bool']]);
add_settings_section('evqra_calendar_display_section', '', null, 'evqra-settings-display');
add_settings_field('evqra_calendar_display_settings', '', [$this, 'render_calendar_display_settings'], 'evqra-settings-display', 'evqra_calendar_display_section');
register_setting('evqra_settings_display', 'evqra_directory_settings', [
'type' => 'array',
'default' => $this->get_directory_defaults(),
'sanitize_callback' => [$this, 'sanitize_directory_settings'],
]);
add_settings_section('evqra_directory_section', '', null, 'evqra-settings-display');
add_settings_field('evqra_directory_settings', '', [$this, 'render_directory_settings'], 'evqra-settings-display', 'evqra_directory_section');
// Email Tab
register_setting('evqra_settings_email', 'evqra_event_email_settings', [
'type' => 'array',
'default' => $this->get_email_defaults(),
'sanitize_callback' => [$this, 'sanitize_email_settings'],
]);
register_setting('evqra_settings_email', 'evqra_disable_admin_emails', ['type' => 'boolean', 'default' => 0, 'sanitize_callback' => [$this, 'sanitize_bool']]);
register_setting('evqra_settings_email', 'evqra_disable_frontend_emails', ['type' => 'boolean', 'default' => 0, 'sanitize_callback' => [$this, 'sanitize_bool']]);
add_settings_section('evqra_email_section', '', null, 'evqra-settings-email');
$emails = [
'user_registration' => 'User Registration Email',
'booking_pending' => 'Booking Pending Email',
'booking_confirmation' => 'Booking Confirmation Email',
'booking_cancellation' => 'Booking Cancellation Email',
'reset_password' => 'Reset Password Email',
'booking_refund' => 'Booking Refund Email',
'frontend_submission' => 'Frontend Event Submission Email',
'frontend_approval' => 'Frontend Submission Approval Email',
'attendee_checkin' => 'Attendee Check-in Email'
];
$default_templates = [
'user_registration' => [
'subject' => 'Welcome to {event_name}, {user_name}!',
'content' => 'Hello {user_name},\n\nThank you for registering for {event_name}. We’re excited to have you with us!' // Add more as needed
],
'booking_pending' => [
'subject' => 'Your booking for {event_name} is pending',
'content' => 'Hi {user_name},\n\nYour booking (ID: {booking_id}) for {event_name} is currently pending. We will notify you upon confirmation.'
],
'booking_confirmation' => [
'subject' => 'Your booking is confirmed: {event_name}',
'content' => 'Hi {user_name},\n\nGreat news! Your booking for {event_name} is confirmed. Booking ID: {booking_id}.'
],
'booking_cancellation' => [
'subject' => 'Booking Cancelled for {event_name}',
'content' => 'Hi {user_name},\n\nYour booking for {event_name} (ID: {booking_id}) has been cancelled.'
],
'reset_password' => [
'subject' => 'Reset Your Password',
'content' => 'Hi {user_name},\n\nTo reset your password, please click the link below.\n\n{reset_link}'
],
'booking_refund' => [
'subject' => 'Refund Processed for {event_name}',
'content' => 'Hi {user_name},\n\nWe have processed your refund for {event_name}. Booking ID: {booking_id}.'
],
'frontend_submission' => [
'subject' => 'Event Submission Received',
'content' => 'Hi {user_name},\n\nWe’ve received your event submission: {event_name}. It is currently under review.'
],
'frontend_approval' => [
'subject' => 'Your Event Has Been Approved',
'content' => 'Hi {user_name},\n\nYour submitted event {event_name} has been approved and published!'
],
'attendee_checkin' => [
'subject' => 'Check-in recorded: {event_name}',
'content' => 'Hi {user_name},\n\nA check-in was recorded for {event_name}.\nChecked in: {quantity}\nTotal checked in: {checked_in_quantity}'
]
];
foreach ($emails as $key => $label) {
add_settings_field($key, esc_html($label), [$this, 'render_email_field'], 'evqra-settings-email', 'evqra_email_section', [
'key' => $key,
'default' => $default_templates[$key],
]);
}
add_settings_field('evqra_disable_admin_emails', __('Disable Admin Emails', 'eventqora'), [$this, 'render_disable_admin_emails'], 'evqra-settings-email', 'evqra_email_section');
add_settings_field('evqra_disable_frontend_emails', __('Disable Frontend Emails', 'eventqora'), [$this, 'render_disable_frontend_emails'], 'evqra-settings-email', 'evqra_email_section');
// Google Maps Tab
register_setting('evqra_settings_google_maps', 'evqra_google_maps_api_key', ['type' => 'string', 'default' => '', 'sanitize_callback' => [$this, 'sanitize_google_maps_key']]);
register_setting('evqra_settings_google_maps', 'evqra_google_maps_zoom', ['type' => 'integer', 'default' => 15, 'sanitize_callback' => [$this, 'sanitize_zoom']]);
register_setting('evqra_settings_google_maps', 'evqra_google_maps_enabled', ['type' => 'boolean', 'default' => 0, 'sanitize_callback' => [$this, 'sanitize_bool']]);
add_settings_section('evqra_google_maps_section', '', null, 'evqra-settings-google_maps');
// API Key
add_settings_field('evqra_google_maps_api_key', __('API Key', 'eventqora'), [$this, 'render_text_input'], 'evqra-settings-google_maps', 'evqra_google_maps_section', [
'id' => 'evqra_google_maps_api_key',
'desc' => __('Enter your Google Maps Embed API key.', 'eventqora')
]);
// Zoom
add_settings_field('evqra_google_maps_zoom', __('Default Zoom Level', 'eventqora'), [$this, 'render_text_input'], 'evqra-settings-google_maps', 'evqra_google_maps_section', [
'id' => 'evqra_google_maps_zoom',
'desc' => __('Recommended between 10–18. Default is 15.', 'eventqora')
]);
// Enabled Toggle
add_settings_field('evqra_google_maps_enabled', __('Enable Map Display', 'eventqora'), [$this, 'render_checkbox_input'], 'evqra-settings-google_maps', 'evqra_google_maps_section');
// PayPal Tab
register_setting('evqra_settings_paypal', 'evqra_paypal_enabled', [
'type' => 'boolean',
'default' => 0,
'sanitize_callback' => function ($value) {
return !empty($value) ? 1 : 0;
},
]);
register_setting('evqra_settings_paypal', 'evqra_paypal_mode', [
'type' => 'string',
'default' => 'sandbox',
'sanitize_callback' => function ($value) {
return $value === 'live' ? 'live' : 'sandbox';
},
]);
register_setting('evqra_settings_paypal', 'evqra_paypal_sandbox_client_id', [
'type' => 'string',
'default' => '',
'sanitize_callback' => [$this, 'sanitize_paypal_credential'],
]);
register_setting('evqra_settings_paypal', 'evqra_paypal_sandbox_secret', [
'type' => 'string',
'default' => '',
'sanitize_callback' => [$this, 'sanitize_paypal_credential'],
]);
register_setting('evqra_settings_paypal', 'evqra_paypal_live_client_id', [
'type' => 'string',
'default' => '',
'sanitize_callback' => [$this, 'sanitize_paypal_credential'],
]);
register_setting('evqra_settings_paypal', 'evqra_paypal_live_secret', [
'type' => 'string',
'default' => '',
'sanitize_callback' => [$this, 'sanitize_paypal_credential'],
]);
register_setting('evqra_settings_paypal', 'evqra_paypal_webhook_id', [
'type' => 'string',
'default' => '',
'sanitize_callback' => [$this, 'sanitize_paypal_webhook_id'],
]);
add_settings_section('evqra_paypal_section', '', null, 'evqra-settings-paypal');
add_settings_field('evqra_paypal_enabled', __('Enable PayPal Payments', 'eventqora'), [$this, 'render_paypal_enabled'], 'evqra-settings-paypal', 'evqra_paypal_section');
// Mode
add_settings_field('evqra_paypal_mode', __('PayPal Mode', 'eventqora'), [$this, 'render_select_input'], 'evqra-settings-paypal', 'evqra_paypal_section', [
'id' => 'evqra_paypal_mode',
'options' => [
'sandbox' => 'Sandbox',
'live' => 'Live'
],
'desc' => __('Select whether to use PayPal in Sandbox (testing) or Live mode for transactions.', 'eventqora')
]);
// Sandbox Client ID
add_settings_field('evqra_paypal_sandbox_client_id', __('Sandbox Client ID', 'eventqora'), [$this, 'render_text_input'], 'evqra-settings-paypal', 'evqra_paypal_section', [
'id' => 'evqra_paypal_sandbox_client_id',
'desc' => __('Enter your PayPal Sandbox Client ID.', 'eventqora')
]);
// Sandbox Secret
add_settings_field('evqra_paypal_sandbox_secret', __('Sandbox Secret', 'eventqora'), [$this, 'render_text_input'], 'evqra-settings-paypal', 'evqra_paypal_section', [
'id' => 'evqra_paypal_sandbox_secret',
'desc' => __('Enter your PayPal Sandbox Secret.', 'eventqora')
]);
// Live Client ID
add_settings_field('evqra_paypal_live_client_id', __('Live Client ID', 'eventqora'), [$this, 'render_text_input'], 'evqra-settings-paypal', 'evqra_paypal_section', [
'id' => 'evqra_paypal_live_client_id',
'desc' => __('Enter your PayPal Live Client ID.', 'eventqora')
]);
// Live Secret
add_settings_field('evqra_paypal_live_secret', __('Live Secret', 'eventqora'), [$this, 'render_text_input'], 'evqra-settings-paypal', 'evqra_paypal_section', [
'id' => 'evqra_paypal_live_secret',
'desc' => __('Enter your PayPal Live Secret.', 'eventqora')
]);
add_settings_field('evqra_paypal_webhook_id', __('PayPal Webhook ID', 'eventqora'), [$this, 'render_text_input'], 'evqra-settings-paypal', 'evqra_paypal_section', [
'id' => 'evqra_paypal_webhook_id',
'desc' => __('Enter the webhook ID created in your PayPal Developer Dashboard. It is required for signed webhook verification.', 'eventqora')
]);
add_settings_field('evqra_paypal_status', __('Configuration Status', 'eventqora'), [$this, 'render_paypal_status'], 'evqra-settings-paypal', 'evqra_paypal_section');
add_settings_field('evqra_paypal_help_note', '', function () {
echo 'Need help creating PayPal credentials? ';
echo 'Visit the PayPal Developer Dashboard to create or manage your sandbox and live API credentials.
';
}, 'evqra-settings-paypal', 'evqra_paypal_section');
}
private function get_directory_defaults() {
return [
'show_view_switcher' => 1,
'categories' => [
'view' => 'cards', 'per_page' => 24, 'columns' => 3,
'show_images' => 1, 'show_count' => 1, 'show_meta' => 1,
],
'venues' => [
'view' => 'cards', 'per_page' => 24, 'columns' => 3,
'show_images' => 1, 'show_count' => 1, 'show_meta' => 1,
],
'organizers' => [
'view' => 'cards', 'per_page' => 24, 'columns' => 3,
'show_images' => 1, 'show_count' => 1, 'show_meta' => 1,
],
];
}
public function sanitize_directory_settings($input) {
$defaults = $this->get_directory_defaults();
$input = is_array($input) ? $input : [];
$output = ['show_view_switcher' => !empty($input['show_view_switcher']) ? 1 : 0];
foreach (['categories', 'venues', 'organizers'] as $type) {
$row = isset($input[$type]) && is_array($input[$type]) ? $input[$type] : [];
$view = isset($row['view']) ? sanitize_key($row['view']) : $defaults[$type]['view'];
if (!in_array($view, ['cards', 'list', 'compact'], true)) {
$view = $defaults[$type]['view'];
}
$per_page = isset($row['per_page']) ? absint($row['per_page']) : $defaults[$type]['per_page'];
$columns = isset($row['columns']) ? absint($row['columns']) : $defaults[$type]['columns'];
$output[$type] = [
'view' => $view,
'per_page' => max(1, min(100, $per_page)),
'columns' => max(2, min(4, $columns)),
'show_images' => !empty($row['show_images']) ? 1 : 0,
'show_count' => !empty($row['show_count']) ? 1 : 0,
'show_meta' => !empty($row['show_meta']) ? 1 : 0,
];
}
return $output;
}
public function render_calendar_display_settings() {
$view = get_option('evqra_default_view', 'month');
$view = sanitize_key($view);
$legacy_views = ['month-view' => 'month', 'week-view' => 'week', 'day-view' => 'day', 'list-view' => 'list'];
$view = $legacy_views[$view] ?? $view;
if (!in_array($view, ['month', 'week', 'day', 'list', 'photo', 'map'], true)) {
$view = 'month';
}
$per_page = max(1, min(200, absint(get_option('evqra_events_per_page', 10))));
$time_format = get_option('evqra_calendar_time_format', 'wordpress');
$time_formats = [
'wordpress' => sprintf(__('Same as WordPress (%s)', 'eventqora'), wp_date(get_option('time_format'), time())),
'24h' => sprintf(__('24-hour (%s)', 'eventqora'), wp_date('H:i', time())),
'12h' => sprintf(__('12-hour (%s)', 'eventqora'), wp_date('g:i a', time())),
];
?>
__('Month', 'eventqora'), 'week' => __('Week', 'eventqora'), 'day' => __('Day', 'eventqora'), 'list' => __('List', 'eventqora'), 'photo' => __('Photo', 'eventqora'), 'map' => __('Map', 'eventqora')] as $key => $label) : ?>
>
$label) : ?>
>
__('Month', 'eventqora'), 'week' => __('Week', 'eventqora'), 'list' => __('List', 'eventqora'), 'photo' => __('Photo', 'eventqora'), 'map' => __('Map', 'eventqora'), 'day' => __('Day', 'eventqora')] as $key => $label) : ?>
/>
render_calendar_checkbox('evqra_calendar_show_filters', __('Show search and filters (category, venue, organizer) above the calendar', 'eventqora'), 1); ?>
>
>
>
Categories.', 'eventqora'); ?>
render_calendar_checkbox('evqra_calendar_full_event_names', __('Show full event names in the month view, wrapping long names onto more lines instead of cutting them short', 'eventqora'), 0); ?>
__('Sunday', 'eventqora'), 1 => __('Monday', 'eventqora'), 2 => __('Tuesday', 'eventqora'), 3 => __('Wednesday', 'eventqora'), 4 => __('Thursday', 'eventqora'), 5 => __('Friday', 'eventqora'), 6 => __('Saturday', 'eventqora')] as $day => $label) : ?>
>
render_calendar_checkbox('evqra_calendar_show_weekends', __('Show weekends', 'eventqora'), 1); ?>
render_calendar_checkbox('evqra_calendar_show_event_end', __('Show event end time', 'eventqora'), 1); ?>
';
echo '' . esc_html($label) . ' ';
}
public function render_directory_settings() {
$settings = wp_parse_args(get_option('evqra_directory_settings', []), $this->get_directory_defaults());
$labels = [
'categories' => [
'title' => __('Categories', 'eventqora'),
'description' => __('Control how visitors browse your event categories.', 'eventqora'),
],
'venues' => [
'title' => __('Venues', 'eventqora'),
'description' => __('Choose the presentation for venue discovery pages.', 'eventqora'),
],
'organizers' => [
'title' => __('Organizers', 'eventqora'),
'description' => __('Choose the presentation for organizer discovery pages.', 'eventqora'),
],
];
echo '';
echo '';
foreach ($labels as $type => $label) {
$row = wp_parse_args($settings[$type] ?? [], $this->get_directory_defaults()[$type]);
echo '
';
echo '' . esc_html($type === 'categories' ? '◈' : ($type === 'venues' ? '⌖' : '◎')) . ' ' . esc_html($label['title']) . ' ' . esc_html($label['description']) . '
';
echo '';
echo '
' . esc_html__('Default layout', 'eventqora') . ' ';
foreach (['cards' => __('Cards / Grid', 'eventqora'), 'list' => __('List', 'eventqora'), 'compact' => __('Compact List', 'eventqora')] as $value => $text) {
echo '' . esc_html($text) . ' ';
}
echo ' ';
echo '
' . esc_html__('Items shown', 'eventqora') . ' ';
echo '
' . esc_html__('Card columns', 'eventqora') . ' ';
foreach ([2, 3, 4] as $columns) {
// translators: Placeholder values in this message are generated event-management data.
echo '' . esc_html(sprintf(__('%d columns', 'eventqora'), $columns)) . ' ';
}
echo ' ';
echo '
';
echo ' ' . esc_html__('Show images', 'eventqora') . ' ';
echo ' ' . esc_html__('Show event count', 'eventqora') . ' ';
echo ' ' . esc_html__('Show secondary details', 'eventqora') . ' ';
echo '
';
}
echo '
';
echo '' . esc_html__('Shortcode overrides still work.', 'eventqora') . ' ' . esc_html__('Use the shortcode attributes when a specific page needs a different result from the global default.', 'eventqora') . '
';
}
/**
* Preserve PayPal credential characters while removing surrounding whitespace.
* PayPal secrets are opaque values and must not be passed through sanitize_text_field().
*/
public function sanitize_paypal_credential($value) {
return is_string($value) ? trim($value) : '';
}
/**
* PayPal webhook IDs are opaque provider identifiers.
*/
public function sanitize_paypal_webhook_id($value) {
return is_string($value) ? sanitize_text_field(trim($value)) : '';
}
/**
* Return a non-secret fingerprint for the currently selected PayPal configuration.
*/
private function paypal_connection_fingerprint($mode, $client, $secret) {
return wp_hash($mode . "\0" . $client . "\0" . $secret, 'auth');
}
public function render_paypal_enabled() {
$enabled = (bool) get_option('evqra_paypal_enabled', 1);
?>
/>
paypal_connection_fingerprint($mode, $client, $secret) : '';
$saved_fingerprint = (string) get_option('evqra_paypal_connection_fingerprint', '');
$connection_state = (string) get_option('evqra_paypal_connection_status', '');
$verified_for_current_credentials = $ready
&& $saved_fingerprint !== ''
&& hash_equals($saved_fingerprint, $fingerprint);
if (!$enabled) {
$label = __('Disabled', 'eventqora');
$class = 'evqra-paypal-status evqra-paypal-status--disabled';
} elseif (!$ready) {
$label = __('Action required', 'eventqora');
$class = 'evqra-paypal-status evqra-paypal-status--warning';
} elseif ($verified_for_current_credentials && $connection_state === 'verified') {
$label = __('Connection verified', 'eventqora');
$class = 'evqra-paypal-status evqra-paypal-status--ready';
} elseif ($verified_for_current_credentials && $connection_state === 'failed') {
$label = __('Connection failed', 'eventqora');
$class = 'evqra-paypal-status evqra-paypal-status--warning';
} else {
$label = __('Credentials configured', 'eventqora');
$class = 'evqra-paypal-status evqra-paypal-status--warning';
}
echo '' . esc_html($label) . ' ' . esc_html(strtoupper($mode)) . ' ';
if ($ready) {
echo '' . esc_html__('Test PayPal Connection', 'eventqora') . '
';
echo '' . esc_html__('Tests OAuth authentication using the saved credentials. No order is created and no payment data is changed.', 'eventqora') . '
';
if ($verified_for_current_credentials && $connection_state === 'verified') {
echo '' . esc_html__('The saved credentials were verified for this environment. Re-run the test after changing credentials or switching environments.', 'eventqora') . '
';
}
echo '
';
?>
' . esc_html__('Add the selected environment Client ID and Secret, save settings, then test the connection before accepting payments.', 'eventqora') . '';
}
}
public function render_text_input($args) {
$defaults = [
'evqra_date_format' => 'Y-m-d',
'evqra_events_per_page' => '10'
];
$value = get_option($args['id'], $defaults[$args['id']] ?? '');
$type = strpos($args['id'] ?? '', 'secret') !== false ? 'password' : 'text';
echo ' ';
if (!empty($args['desc'])) {
echo '' . esc_html($args['desc']) . '
';
}
}
public function render_select_input($args) {
$id = isset($args['id']) ? $args['id'] : '';
$options = isset($args['options']) && is_array($args['options']) ? $args['options'] : [];
$value = get_option($id, '');
echo '';
foreach ($options as $key => $label) {
echo '' . esc_html($label) . ' ';
}
echo ' ';
if (!empty($args['desc'])) {
echo '' . wp_kses_post($args['desc']) . '
';
}
}
public function render_checkbox_input($args) {
$value = get_option('evqra_google_maps_enabled', 0);
?>
/>
get_email_defaults();
$settings = get_option('evqra_event_email_settings', []);
if (!is_array($settings)) {
$settings = [];
}
$changed = false;
foreach ($defaults as $key => $default) {
if (!isset($settings[$key]) || !is_array($settings[$key])) {
$settings[$key] = $default;
$changed = true;
continue;
}
if (!isset($settings[$key]['enabled'])) {
$settings[$key]['enabled'] = $default['enabled'];
$changed = true;
}
if (empty($settings[$key]['subject'])) {
$settings[$key]['subject'] = $default['subject'];
$changed = true;
}
if (empty($settings[$key]['content'])) {
$settings[$key]['content'] = $default['content'];
$changed = true;
}
}
if ($changed) {
update_option('evqra_event_email_settings', $settings);
}
}
public function get_email_defaults() {
return [
'user_registration' => [
'enabled' => 0,
'subject' => 'Welcome to {event_name}, {user_name}!',
'content' => "Hello {user_name},\n\nThank you for registering for {event_name}. We’re excited to have you with us!",
],
'booking_pending' => [
'enabled' => 1,
'subject' => 'Your booking for {event_name} is pending',
'content' => "Hi {user_name},\n\nYour booking (ID: {booking_id}) for {event_name} is currently pending. We will notify you upon confirmation.",
],
'booking_confirmation' => [
'enabled' => 1,
'subject' => 'Your booking is confirmed: {event_name}',
'content' => "Hi {user_name},\n\nGreat news! Your booking for {event_name} is confirmed. Booking ID: {booking_id}.",
],
'booking_cancellation' => [
'enabled' => 1,
'subject' => 'Booking Cancelled for {event_name}',
'content' => "Hi {user_name},\n\nYour booking for {event_name} (ID: {booking_id}) has been cancelled.",
],
'reset_password' => [
'enabled' => 0,
'subject' => 'Reset Your Password',
'content' => "Hi {user_name},\n\nTo reset your password, please click the link below.\n\n{reset_link}",
],
'booking_refund' => [
'enabled' => 1,
'subject' => 'Refund Processed for {event_name}',
'content' => "Hi {user_name},\n\nWe have processed your refund for {event_name}. Booking ID: {booking_id}.",
],
'frontend_submission' => [
'enabled' => 0,
'subject' => 'Event Submission Received',
'content' => "Hi {user_name},\n\nWe’ve received your event submission: {event_name}. It is currently under review.",
],
'frontend_approval' => [
'enabled' => 0,
'subject' => 'Your Event Has Been Approved',
'content' => "Hi {user_name},\n\nYour submitted event {event_name} has been approved and published!",
],
'attendee_checkin' => [
'enabled' => 0,
'subject' => 'Check-in recorded: {event_name}',
'content' => "Hi {user_name},\n\nA check-in was recorded for {event_name}.\nChecked in: {quantity}\nTotal checked in: {checked_in_quantity}",
],
];
}
public function sanitize_email_settings($input) {
$defaults = $this->get_email_defaults();
$input = is_array($input) ? $input : [];
$output = [];
foreach ($defaults as $key => $default) {
$row = isset($input[$key]) && is_array($input[$key]) ? $input[$key] : [];
$subject = isset($row['subject']) ? sanitize_text_field($row['subject']) : '';
$content = isset($row['content']) ? sanitize_textarea_field($row['content']) : '';
$output[$key] = [
'enabled' => !empty($row['enabled']) ? 1 : 0,
// Keep a useful template whenever the administrator leaves a field empty.
'subject' => $subject !== '' ? $subject : $default['subject'],
'content' => $content !== '' ? $content : $default['content'],
];
}
return $output;
}
public function render_email_field($args) {
$defaults = $this->get_email_defaults();
$options = get_option('evqra_event_email_settings', []);
$key = sanitize_key($args['key'] ?? '');
$data = isset($options[$key]) && is_array($options[$key]) ? wp_parse_args($options[$key], $defaults[$key] ?? []) : ($defaults[$key] ?? []);
// Treat an explicitly empty saved field as "use the default template".
if (isset($defaults[$key])) {
if (empty($data['subject'])) {
$data['subject'] = $defaults[$key]['subject'];
}
if (empty($data['content'])) {
$data['content'] = $defaults[$key]['content'];
}
}
$enabled = !empty($data['enabled']);
$labels = [
'user_registration' => __('User Registration Email', 'eventqora'),
'booking_pending' => __('Booking Pending Email', 'eventqora'),
'booking_confirmation' => __('Booking Confirmation Email', 'eventqora'),
'booking_cancellation' => __('Booking Cancellation Email', 'eventqora'),
'reset_password' => __('Reset Password Email', 'eventqora'),
'booking_refund' => __('Booking Refund Email', 'eventqora'),
'frontend_submission' => __('Frontend Event Submission Email', 'eventqora'),
'frontend_approval' => __('Frontend Submission Approval Email', 'eventqora'),
'attendee_checkin' => __('Attendee Check-in Email', 'eventqora'),
];
$status = $enabled ? __('Enabled', 'eventqora') : __('Disabled', 'eventqora');
$event_names = [
'user_registration' => __('Account / registration', 'eventqora'),
'booking_pending' => __('Booking lifecycle', 'eventqora'),
'booking_confirmation' => __('Booking lifecycle', 'eventqora'),
'booking_cancellation' => __('Booking lifecycle', 'eventqora'),
'reset_password' => __('Account / password', 'eventqora'),
'booking_refund' => __('Payment / refund', 'eventqora'),
'frontend_submission' => __('Frontend submissions', 'eventqora'),
'frontend_approval' => __('Frontend submissions', 'eventqora'),
'attendee_checkin' => __('Attendee check-in', 'eventqora'),
];
$future_notifications = [
'user_registration',
'reset_password',
'frontend_submission',
'frontend_approval',
];
$is_future = in_array($key, $future_notifications, true);
$description = $event_names[$key] ?? __('Notification', 'eventqora');
?>
/>
/>