Bidirectional sync between Eventbrite and The Events Calendar, with WooCommerce ticket purchasing that bypasses Eventbrite's processing fees by registering buyers as free attendees via API. Includes venue/ organizer sync, QR code ticket generation, attendee management with CSV export, scheduled sync via WP-Cron, and real-time Eventbrite webhooks.
547 lines
21 KiB
PHP
547 lines
21 KiB
PHP
<?php
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
final class EB4TEC_Settings {
|
|
|
|
public function __construct() {
|
|
add_action( 'admin_menu', [ $this, 'add_admin_menu' ] );
|
|
add_action( 'admin_post_eb4tec_save_settings', [ $this, 'handle_settings_save' ] );
|
|
add_action( 'wp_ajax_eb4tec_validate_token', [ $this, 'ajax_validate_token' ] );
|
|
add_action( 'wp_ajax_eb4tec_register_webhook', [ $this, 'ajax_register_webhook' ] );
|
|
add_action( 'wp_ajax_eb4tec_delete_webhook', [ $this, 'ajax_delete_webhook' ] );
|
|
add_action( 'admin_enqueue_scripts', [ $this, 'admin_enqueue_scripts' ] );
|
|
add_action( 'admin_notices', [ $this, 'admin_notices' ] );
|
|
}
|
|
|
|
public function add_admin_menu(): void {
|
|
add_submenu_page(
|
|
'edit.php?post_type=tribe_events',
|
|
__( 'Eventbrite Sync', 'eb4tec' ),
|
|
__( 'Eventbrite Sync', 'eb4tec' ),
|
|
'manage_options',
|
|
'eb4tec-settings',
|
|
[ $this, 'render_settings_page' ]
|
|
);
|
|
|
|
// Attendees submenu page is registered by EB4TEC_Attendees.
|
|
}
|
|
|
|
public function render_settings_page(): void {
|
|
if ( ! current_user_can( 'manage_options' ) ) {
|
|
return;
|
|
}
|
|
|
|
$active_tab = sanitize_key( $_GET['tab'] ?? 'api' );
|
|
$org_name = esc_html( get_option( 'eb4tec_org_name', '' ) );
|
|
$last_sync = (int) get_option( 'eb4tec_last_sync_timestamp', 0 );
|
|
$sync_result = get_transient( 'eb4tec_last_sync_result' );
|
|
|
|
echo '<div class="wrap">';
|
|
echo '<h1>' . esc_html__( 'Eventbrite for The Events Calendar', 'eb4tec' ) . '</h1>';
|
|
|
|
// Sync status bar.
|
|
if ( $last_sync ) {
|
|
$sync_time = human_time_diff( $last_sync );
|
|
echo '<p class="description">';
|
|
printf(
|
|
esc_html__( 'Last sync: %s ago', 'eb4tec' ),
|
|
esc_html( $sync_time )
|
|
);
|
|
if ( is_array( $sync_result ) ) {
|
|
printf(
|
|
' — ' . esc_html__( '%d pulled, %d pushed, %d errors.', 'eb4tec' ),
|
|
(int) ( $sync_result['pulled'] ?? 0 ),
|
|
(int) ( $sync_result['pushed'] ?? 0 ),
|
|
(int) ( $sync_result['errors'] ?? 0 )
|
|
);
|
|
}
|
|
echo '</p>';
|
|
}
|
|
|
|
// Sync Now button.
|
|
echo '<form method="post" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '" style="display:inline-block;margin-bottom:12px;">';
|
|
wp_nonce_field( 'eb4tec_sync_now', '_eb4tec_sync_nonce' );
|
|
echo '<input type="hidden" name="action" value="eb4tec_sync_now">';
|
|
submit_button( __( 'Sync Now', 'eb4tec' ), 'secondary', 'submit', false );
|
|
echo '</form>';
|
|
|
|
// Tabs.
|
|
$tabs = [
|
|
'api' => __( 'API & Credentials', 'eb4tec' ),
|
|
'sync' => __( 'Sync Settings', 'eb4tec' ),
|
|
'woocommerce' => __( 'WooCommerce', 'eb4tec' ),
|
|
];
|
|
|
|
echo '<nav class="nav-tab-wrapper">';
|
|
foreach ( $tabs as $slug => $label ) {
|
|
$class = ( $slug === $active_tab ) ? 'nav-tab nav-tab-active' : 'nav-tab';
|
|
$url = add_query_arg( [ 'page' => 'eb4tec-settings', 'tab' => $slug ], admin_url( 'edit.php?post_type=tribe_events' ) );
|
|
printf( '<a href="%s" class="%s">%s</a>', esc_url( $url ), esc_attr( $class ), esc_html( $label ) );
|
|
}
|
|
echo '</nav>';
|
|
|
|
echo '<form method="post" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '">';
|
|
wp_nonce_field( 'eb4tec_save_settings', '_eb4tec_settings_nonce' );
|
|
echo '<input type="hidden" name="action" value="eb4tec_save_settings">';
|
|
echo '<input type="hidden" name="eb4tec_tab" value="' . esc_attr( $active_tab ) . '">';
|
|
|
|
echo '<table class="form-table" role="presentation"><tbody>';
|
|
|
|
match ( $active_tab ) {
|
|
'api' => $this->render_tab_api( $org_name ),
|
|
'sync' => $this->render_tab_sync(),
|
|
'woocommerce' => $this->render_tab_woocommerce(),
|
|
default => $this->render_tab_api( $org_name ),
|
|
};
|
|
|
|
echo '</tbody></table>';
|
|
|
|
submit_button();
|
|
echo '</form>';
|
|
echo '</div>';
|
|
}
|
|
|
|
private function render_tab_api( string $org_name ): void {
|
|
$token = get_option( 'eb4tec_api_token', '' );
|
|
$token_display = $token ? str_repeat( '•', 20 ) : '';
|
|
$org_id = esc_attr( get_option( 'eb4tec_org_id', '' ) );
|
|
|
|
?>
|
|
<tr>
|
|
<th scope="row"><label for="eb4tec_api_token"><?php esc_html_e( 'Eventbrite API Token', 'eb4tec' ); ?></label></th>
|
|
<td>
|
|
<input type="password" id="eb4tec_api_token" name="eb4tec_api_token"
|
|
class="regular-text" value="<?php echo esc_attr( $token_display ); ?>"
|
|
placeholder="<?php esc_attr_e( 'Paste your private token here', 'eb4tec' ); ?>"
|
|
autocomplete="new-password">
|
|
<p class="description">
|
|
<?php esc_html_e( 'Find your token at eventbrite.com → Account Settings → Developer Links → API Keys.', 'eb4tec' ); ?>
|
|
</p>
|
|
<button type="button" id="eb4tec-validate-token" class="button button-secondary" style="margin-top:6px;">
|
|
<?php esc_html_e( 'Validate & Fetch Organization', 'eb4tec' ); ?>
|
|
</button>
|
|
<span id="eb4tec-validate-result" style="margin-left:8px;"></span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row"><label for="eb4tec_org_id"><?php esc_html_e( 'Organization ID', 'eb4tec' ); ?></label></th>
|
|
<td>
|
|
<input type="text" id="eb4tec_org_id" name="eb4tec_org_id"
|
|
class="regular-text" value="<?php echo $org_id; ?>">
|
|
<?php if ( $org_name ) : ?>
|
|
<p class="description"><?php echo esc_html( sprintf( __( 'Connected: %s', 'eb4tec' ), $org_name ) ); ?></p>
|
|
<?php endif; ?>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row"><?php esc_html_e( 'Webhook URL', 'eb4tec' ); ?></th>
|
|
<td>
|
|
<code><?php echo esc_url( add_query_arg( 'eb4tec_webhook', '1', home_url( '/' ) ) ); ?></code>
|
|
<br><br>
|
|
<button type="button" id="eb4tec-register-webhook" class="button button-secondary">
|
|
<?php esc_html_e( 'Register Webhook with Eventbrite', 'eb4tec' ); ?>
|
|
</button>
|
|
<button type="button" id="eb4tec-delete-webhook" class="button button-secondary" style="margin-left:6px;">
|
|
<?php esc_html_e( 'Remove Webhook', 'eb4tec' ); ?>
|
|
</button>
|
|
<span id="eb4tec-webhook-result" style="margin-left:8px;"></span>
|
|
<p class="description"><?php esc_html_e( 'Register this URL with Eventbrite to receive real-time event updates.', 'eb4tec' ); ?></p>
|
|
</td>
|
|
</tr>
|
|
<?php
|
|
}
|
|
|
|
private function render_tab_sync(): void {
|
|
$interval = get_option( 'eb4tec_sync_interval', 'hourly' );
|
|
$direction = get_option( 'eb4tec_sync_direction', 'both' );
|
|
$label = get_option( 'eb4tec_wp_ticket_label', 'WordPress Purchase' );
|
|
$visible = get_option( 'eb4tec_wp_ticket_visible', 'hidden' );
|
|
$publish = get_option( 'eb4tec_auto_publish', '1' );
|
|
$venues = get_option( 'eb4tec_sync_venues', '1' );
|
|
$orgs = get_option( 'eb4tec_sync_organizers', '1' );
|
|
|
|
$intervals = [
|
|
'hourly' => __( 'Hourly', 'eb4tec' ),
|
|
'twicedaily' => __( 'Twice Daily', 'eb4tec' ),
|
|
'daily' => __( 'Daily', 'eb4tec' ),
|
|
];
|
|
$directions = [
|
|
'both' => __( 'Both directions', 'eb4tec' ),
|
|
'eb_to_tec' => __( 'Eventbrite → WordPress only', 'eb4tec' ),
|
|
'tec_to_eb' => __( 'WordPress → Eventbrite only', 'eb4tec' ),
|
|
];
|
|
?>
|
|
<tr>
|
|
<th scope="row"><label for="eb4tec_sync_interval"><?php esc_html_e( 'Sync Interval', 'eb4tec' ); ?></label></th>
|
|
<td>
|
|
<select id="eb4tec_sync_interval" name="eb4tec_sync_interval">
|
|
<?php foreach ( $intervals as $val => $label_text ) : ?>
|
|
<option value="<?php echo esc_attr( $val ); ?>" <?php selected( $interval, $val ); ?>>
|
|
<?php echo esc_html( $label_text ); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row"><label for="eb4tec_sync_direction"><?php esc_html_e( 'Sync Direction', 'eb4tec' ); ?></label></th>
|
|
<td>
|
|
<select id="eb4tec_sync_direction" name="eb4tec_sync_direction">
|
|
<?php foreach ( $directions as $val => $label_text ) : ?>
|
|
<option value="<?php echo esc_attr( $val ); ?>" <?php selected( $direction, $val ); ?>>
|
|
<?php echo esc_html( $label_text ); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row"><label for="eb4tec_wp_ticket_label"><?php esc_html_e( 'WordPress Ticket Label on Eventbrite', 'eb4tec' ); ?></label></th>
|
|
<td>
|
|
<input type="text" id="eb4tec_wp_ticket_label" name="eb4tec_wp_ticket_label"
|
|
class="regular-text" value="<?php echo esc_attr( $label ); ?>">
|
|
<p class="description"><?php esc_html_e( 'The name of the hidden free ticket class created on Eventbrite for WordPress purchases.', 'eb4tec' ); ?></p>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row"><label for="eb4tec_wp_ticket_visible"><?php esc_html_e( 'WordPress Ticket Visibility on Eventbrite', 'eb4tec' ); ?></label></th>
|
|
<td>
|
|
<select id="eb4tec_wp_ticket_visible" name="eb4tec_wp_ticket_visible">
|
|
<option value="hidden" <?php selected( $visible, 'hidden' ); ?>><?php esc_html_e( 'Hidden (recommended)', 'eb4tec' ); ?></option>
|
|
<option value="visible" <?php selected( $visible, 'visible' ); ?>><?php esc_html_e( 'Visible', 'eb4tec' ); ?></option>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row"><?php esc_html_e( 'Auto-publish Events', 'eb4tec' ); ?></th>
|
|
<td>
|
|
<label>
|
|
<input type="checkbox" name="eb4tec_auto_publish" value="1" <?php checked( $publish, '1' ); ?>>
|
|
<?php esc_html_e( 'Automatically publish events pushed to Eventbrite', 'eb4tec' ); ?>
|
|
</label>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row"><?php esc_html_e( 'Sync Venues', 'eb4tec' ); ?></th>
|
|
<td>
|
|
<label>
|
|
<input type="checkbox" name="eb4tec_sync_venues" value="1" <?php checked( $venues, '1' ); ?>>
|
|
<?php esc_html_e( 'Sync venue data between Eventbrite and The Events Calendar', 'eb4tec' ); ?>
|
|
</label>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row"><?php esc_html_e( 'Sync Organizers', 'eb4tec' ); ?></th>
|
|
<td>
|
|
<label>
|
|
<input type="checkbox" name="eb4tec_sync_organizers" value="1" <?php checked( $orgs, '1' ); ?>>
|
|
<?php esc_html_e( 'Sync organizer data between Eventbrite and The Events Calendar', 'eb4tec' ); ?>
|
|
</label>
|
|
</td>
|
|
</tr>
|
|
<?php
|
|
}
|
|
|
|
private function render_tab_woocommerce(): void {
|
|
$cat_id = (int) get_option( 'eb4tec_woo_category_id', 0 );
|
|
$qr_size = (int) get_option( 'eb4tec_qr_size', 200 );
|
|
$qr_in_email = get_option( 'eb4tec_qr_in_email', '1' );
|
|
$qr_on_order = get_option( 'eb4tec_qr_on_order_page', '1' );
|
|
$delete_data = get_option( 'eb4tec_delete_on_uninstall', '' );
|
|
|
|
$categories = get_terms( [
|
|
'taxonomy' => 'product_cat',
|
|
'hide_empty' => false,
|
|
] );
|
|
?>
|
|
<tr>
|
|
<th scope="row"><label for="eb4tec_woo_category_id"><?php esc_html_e( 'Ticket Product Category', 'eb4tec' ); ?></label></th>
|
|
<td>
|
|
<select id="eb4tec_woo_category_id" name="eb4tec_woo_category_id">
|
|
<option value="0"><?php esc_html_e( '— None —', 'eb4tec' ); ?></option>
|
|
<?php if ( ! is_wp_error( $categories ) ) : ?>
|
|
<?php foreach ( $categories as $cat ) : ?>
|
|
<option value="<?php echo esc_attr( $cat->term_id ); ?>" <?php selected( $cat_id, $cat->term_id ); ?>>
|
|
<?php echo esc_html( $cat->name ); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</select>
|
|
<p class="description"><?php esc_html_e( 'WooCommerce products created for event tickets will be assigned to this category.', 'eb4tec' ); ?></p>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row"><label for="eb4tec_qr_size"><?php esc_html_e( 'QR Code Size (px)', 'eb4tec' ); ?></label></th>
|
|
<td>
|
|
<input type="number" id="eb4tec_qr_size" name="eb4tec_qr_size"
|
|
value="<?php echo esc_attr( $qr_size ); ?>" min="100" max="500" step="10" class="small-text">
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row"><?php esc_html_e( 'QR Code in Email', 'eb4tec' ); ?></th>
|
|
<td>
|
|
<label>
|
|
<input type="checkbox" name="eb4tec_qr_in_email" value="1" <?php checked( $qr_in_email, '1' ); ?>>
|
|
<?php esc_html_e( 'Include QR code in the WooCommerce order confirmation email', 'eb4tec' ); ?>
|
|
</label>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row"><?php esc_html_e( 'QR Code on Order Page', 'eb4tec' ); ?></th>
|
|
<td>
|
|
<label>
|
|
<input type="checkbox" name="eb4tec_qr_on_order_page" value="1" <?php checked( $qr_on_order, '1' ); ?>>
|
|
<?php esc_html_e( 'Show QR code on the order confirmation / thank-you page', 'eb4tec' ); ?>
|
|
</label>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row"><?php esc_html_e( 'Delete Data on Uninstall', 'eb4tec' ); ?></th>
|
|
<td>
|
|
<label>
|
|
<input type="checkbox" name="eb4tec_delete_on_uninstall" value="1" <?php checked( $delete_data, '1' ); ?>>
|
|
<?php esc_html_e( 'Remove all plugin settings and post meta when the plugin is deleted', 'eb4tec' ); ?>
|
|
</label>
|
|
</td>
|
|
</tr>
|
|
<?php
|
|
}
|
|
|
|
public function handle_settings_save(): void {
|
|
if ( ! current_user_can( 'manage_options' ) ) {
|
|
wp_die( esc_html__( 'Insufficient permissions.', 'eb4tec' ) );
|
|
}
|
|
|
|
check_admin_referer( 'eb4tec_save_settings', '_eb4tec_settings_nonce' );
|
|
|
|
$tab = sanitize_key( $_POST['eb4tec_tab'] ?? 'api' );
|
|
|
|
if ( 'api' === $tab ) {
|
|
$raw_token = $_POST['eb4tec_api_token'] ?? '';
|
|
// Only update if a real value was submitted (not the masked placeholder).
|
|
if ( $raw_token && ! str_contains( $raw_token, '•' ) ) {
|
|
update_option( 'eb4tec_api_token', sanitize_text_field( $raw_token ), false );
|
|
}
|
|
update_option( 'eb4tec_org_id', sanitize_text_field( $_POST['eb4tec_org_id'] ?? '' ) );
|
|
}
|
|
|
|
if ( 'sync' === $tab ) {
|
|
$interval = sanitize_key( $_POST['eb4tec_sync_interval'] ?? 'hourly' );
|
|
if ( ! in_array( $interval, [ 'hourly', 'twicedaily', 'daily' ], true ) ) {
|
|
$interval = 'hourly';
|
|
}
|
|
$old_interval = get_option( 'eb4tec_sync_interval', 'hourly' );
|
|
update_option( 'eb4tec_sync_interval', $interval );
|
|
if ( $interval !== $old_interval ) {
|
|
EB4TEC_Cron::unschedule();
|
|
EB4TEC_Cron::schedule();
|
|
}
|
|
|
|
$direction = sanitize_key( $_POST['eb4tec_sync_direction'] ?? 'both' );
|
|
if ( ! in_array( $direction, [ 'both', 'eb_to_tec', 'tec_to_eb' ], true ) ) {
|
|
$direction = 'both';
|
|
}
|
|
update_option( 'eb4tec_sync_direction', $direction );
|
|
update_option( 'eb4tec_wp_ticket_label', sanitize_text_field( $_POST['eb4tec_wp_ticket_label'] ?? 'WordPress Purchase' ) );
|
|
$visible = sanitize_key( $_POST['eb4tec_wp_ticket_visible'] ?? 'hidden' );
|
|
update_option( 'eb4tec_wp_ticket_visible', in_array( $visible, [ 'hidden', 'visible' ], true ) ? $visible : 'hidden' );
|
|
update_option( 'eb4tec_auto_publish', isset( $_POST['eb4tec_auto_publish'] ) ? '1' : '' );
|
|
update_option( 'eb4tec_sync_venues', isset( $_POST['eb4tec_sync_venues'] ) ? '1' : '' );
|
|
update_option( 'eb4tec_sync_organizers', isset( $_POST['eb4tec_sync_organizers'] ) ? '1' : '' );
|
|
}
|
|
|
|
if ( 'woocommerce' === $tab ) {
|
|
update_option( 'eb4tec_woo_category_id', absint( $_POST['eb4tec_woo_category_id'] ?? 0 ) );
|
|
$qr_size = max( 100, min( 500, (int) ( $_POST['eb4tec_qr_size'] ?? 200 ) ) );
|
|
update_option( 'eb4tec_qr_size', $qr_size );
|
|
update_option( 'eb4tec_qr_in_email', isset( $_POST['eb4tec_qr_in_email'] ) ? '1' : '' );
|
|
update_option( 'eb4tec_qr_on_order_page', isset( $_POST['eb4tec_qr_on_order_page'] ) ? '1' : '' );
|
|
update_option( 'eb4tec_delete_on_uninstall', isset( $_POST['eb4tec_delete_on_uninstall'] ) ? '1' : '' );
|
|
}
|
|
|
|
$redirect = add_query_arg( [
|
|
'page' => 'eb4tec-settings',
|
|
'tab' => $tab,
|
|
'updated' => '1',
|
|
], admin_url( 'edit.php?post_type=tribe_events' ) );
|
|
|
|
wp_safe_redirect( $redirect );
|
|
exit;
|
|
}
|
|
|
|
public function ajax_validate_token(): void {
|
|
check_ajax_referer( 'eb4tec_admin_ajax', 'nonce' );
|
|
|
|
if ( ! current_user_can( 'manage_options' ) ) {
|
|
wp_send_json_error( [ 'message' => __( 'Insufficient permissions.', 'eb4tec' ) ] );
|
|
}
|
|
|
|
$token = sanitize_text_field( $_POST['token'] ?? '' );
|
|
if ( empty( $token ) ) {
|
|
wp_send_json_error( [ 'message' => __( 'No token provided.', 'eb4tec' ) ] );
|
|
}
|
|
|
|
// Temporarily update the token so the API client picks it up.
|
|
$old_token = get_option( 'eb4tec_api_token', '' );
|
|
update_option( 'eb4tec_api_token', $token, false );
|
|
|
|
$api = new EB4TEC_API_Client();
|
|
$result = $api->get_user_me();
|
|
|
|
if ( is_wp_error( $result ) ) {
|
|
update_option( 'eb4tec_api_token', $old_token, false );
|
|
wp_send_json_error( [ 'message' => $result->get_error_message() ] );
|
|
}
|
|
|
|
// Fetch organization ID.
|
|
$orgs = isset( $result['organizations'] ) ? $result['organizations'] : [];
|
|
if ( empty( $orgs ) ) {
|
|
// Try getting org from user profile.
|
|
$org_id = '';
|
|
$org_name = $result['name'] ?? '';
|
|
} else {
|
|
$org = reset( $orgs );
|
|
$org_id = $org['id'] ?? '';
|
|
$org_name = $org['name'] ?? '';
|
|
}
|
|
|
|
update_option( 'eb4tec_org_id', sanitize_text_field( $org_id ) );
|
|
update_option( 'eb4tec_org_name', sanitize_text_field( $org_name ) );
|
|
|
|
wp_send_json_success( [
|
|
'message' => sprintf( __( 'Connected as %s (Org: %s)', 'eb4tec' ), esc_html( $result['name'] ?? '' ), esc_html( $org_name ) ),
|
|
'org_id' => $org_id,
|
|
'org_name' => $org_name,
|
|
] );
|
|
}
|
|
|
|
public function ajax_register_webhook(): void {
|
|
check_ajax_referer( 'eb4tec_admin_ajax', 'nonce' );
|
|
|
|
if ( ! current_user_can( 'manage_options' ) ) {
|
|
wp_send_json_error( [ 'message' => __( 'Insufficient permissions.', 'eb4tec' ) ] );
|
|
}
|
|
|
|
$secret = get_option( 'eb4tec_webhook_secret', '' );
|
|
if ( empty( $secret ) ) {
|
|
$secret = wp_generate_password( 32, false );
|
|
update_option( 'eb4tec_webhook_secret', $secret );
|
|
}
|
|
|
|
$endpoint_url = add_query_arg( 'eb4tec_webhook', '1', home_url( '/' ) );
|
|
$api = new EB4TEC_API_Client();
|
|
|
|
$result = $api->create_webhook( [
|
|
'webhook' => [
|
|
'endpoint_url' => $endpoint_url,
|
|
'actions' => 'event.created,event.published,event.updated,event.unpublished,attendee.updated',
|
|
],
|
|
] );
|
|
|
|
if ( is_wp_error( $result ) ) {
|
|
wp_send_json_error( [ 'message' => $result->get_error_message() ] );
|
|
}
|
|
|
|
update_option( 'eb4tec_webhook_id', sanitize_text_field( $result['id'] ?? '' ) );
|
|
wp_send_json_success( [ 'message' => __( 'Webhook registered successfully.', 'eb4tec' ) ] );
|
|
}
|
|
|
|
public function ajax_delete_webhook(): void {
|
|
check_ajax_referer( 'eb4tec_admin_ajax', 'nonce' );
|
|
|
|
if ( ! current_user_can( 'manage_options' ) ) {
|
|
wp_send_json_error( [ 'message' => __( 'Insufficient permissions.', 'eb4tec' ) ] );
|
|
}
|
|
|
|
$webhook_id = get_option( 'eb4tec_webhook_id', '' );
|
|
if ( empty( $webhook_id ) ) {
|
|
wp_send_json_error( [ 'message' => __( 'No webhook ID stored.', 'eb4tec' ) ] );
|
|
}
|
|
|
|
$api = new EB4TEC_API_Client();
|
|
$result = $api->delete_webhook( $webhook_id );
|
|
|
|
if ( is_wp_error( $result ) ) {
|
|
wp_send_json_error( [ 'message' => $result->get_error_message() ] );
|
|
}
|
|
|
|
delete_option( 'eb4tec_webhook_id' );
|
|
wp_send_json_success( [ 'message' => __( 'Webhook removed.', 'eb4tec' ) ] );
|
|
}
|
|
|
|
public function admin_enqueue_scripts( string $hook ): void {
|
|
$screen = get_current_screen();
|
|
if ( ! $screen || ! str_contains( $screen->id ?? '', 'eb4tec' ) ) {
|
|
return;
|
|
}
|
|
|
|
$nonce = wp_create_nonce( 'eb4tec_admin_ajax' );
|
|
wp_add_inline_script(
|
|
'jquery',
|
|
"(function($){ const nonce = '{$nonce}';
|
|
$('#eb4tec-validate-token').on('click', function(){
|
|
var token = $('#eb4tec_api_token').val();
|
|
$.post(ajaxurl, {action:'eb4tec_validate_token',nonce:nonce,token:token}, function(r){
|
|
var el = $('#eb4tec-validate-result');
|
|
if(r.success){ el.css('color','green').text(r.data.message); $('#eb4tec_org_id').val(r.data.org_id); }
|
|
else { el.css('color','red').text(r.data.message); }
|
|
});
|
|
});
|
|
$('#eb4tec-register-webhook').on('click', function(){
|
|
$.post(ajaxurl, {action:'eb4tec_register_webhook',nonce:nonce}, function(r){
|
|
var el = $('#eb4tec-webhook-result');
|
|
if(r.success){ el.css('color','green').text(r.data.message); }
|
|
else { el.css('color','red').text(r.data.message); }
|
|
});
|
|
});
|
|
$('#eb4tec-delete-webhook').on('click', function(){
|
|
$.post(ajaxurl, {action:'eb4tec_delete_webhook',nonce:nonce}, function(r){
|
|
var el = $('#eb4tec-webhook-result');
|
|
if(r.success){ el.css('color','green').text(r.data.message); }
|
|
else { el.css('color','red').text(r.data.message); }
|
|
});
|
|
});
|
|
})(jQuery);"
|
|
);
|
|
}
|
|
|
|
public function admin_notices(): void {
|
|
if ( ! current_user_can( 'manage_options' ) ) {
|
|
return;
|
|
}
|
|
|
|
$screen = get_current_screen();
|
|
if ( ! $screen || ! str_contains( $screen->id ?? '', 'eb4tec' ) ) {
|
|
return;
|
|
}
|
|
|
|
if ( ! empty( $_GET['updated'] ) ) {
|
|
echo '<div class="notice notice-success is-dismissible"><p>' .
|
|
esc_html__( 'Settings saved.', 'eb4tec' ) .
|
|
'</p></div>';
|
|
}
|
|
|
|
if ( get_transient( 'eb4tec_rate_limit_warning' ) ) {
|
|
echo '<div class="notice notice-warning is-dismissible"><p>' .
|
|
esc_html__( 'Eventbrite API rate limit is nearly exhausted. Sync operations may be delayed.', 'eb4tec' ) .
|
|
'</p></div>';
|
|
}
|
|
|
|
// Show "Sync Now" result.
|
|
$user_id = get_current_user_id();
|
|
$sync_result = get_transient( "eb4tec_sync_now_result_{$user_id}" );
|
|
if ( is_array( $sync_result ) ) {
|
|
delete_transient( "eb4tec_sync_now_result_{$user_id}" );
|
|
$msg = sprintf(
|
|
__( 'Sync complete — %d pulled from Eventbrite, %d pushed to Eventbrite, %d errors.', 'eb4tec' ),
|
|
(int) ( $sync_result['pulled'] ?? 0 ),
|
|
(int) ( $sync_result['pushed'] ?? 0 ),
|
|
(int) ( $sync_result['errors'] ?? 0 )
|
|
);
|
|
$class = ( ( $sync_result['errors'] ?? 0 ) > 0 ) ? 'notice-warning' : 'notice-success';
|
|
echo '<div class="notice ' . esc_attr( $class ) . ' is-dismissible"><p>' . esc_html( $msg ) . '</p></div>';
|
|
}
|
|
}
|
|
}
|