initial
This commit is contained in:
+139
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: Reservair
|
||||
* Description: A reservation and booking system for WordPress. Site visitors browse available time slots and submit reservation requests via a Gutenberg block; administrators manage timetables, services, forms, and reservations from the WordPress admin panel.
|
||||
* Version: 0.1.0
|
||||
* Requires at least: 6.7
|
||||
* Requires PHP: 7.4
|
||||
* Author: Martin Slachta
|
||||
* License: GPL-2.0-or-later
|
||||
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
||||
* Text Domain: reservair
|
||||
*
|
||||
* @package reservair
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
require_once __DIR__ . '/admin.php';
|
||||
|
||||
register_activation_hook( __FILE__, [ 'RsvInstaller', 'install' ] );
|
||||
|
||||
/**
|
||||
* Wires up the plugin's runtime services on `plugins_loaded` instead of at
|
||||
* file-include time, so that nothing is instantiated until WordPress (and any
|
||||
* plugins we might interact with) is fully loaded.
|
||||
*/
|
||||
function rsv_bootstrap(): void {
|
||||
global $rsv_form_registry;
|
||||
|
||||
// Re-grant the custom capability after a plugin *update* (the activation hook
|
||||
// only runs on activate). No-op once the stored version matches.
|
||||
RsvCapabilities::ensure();
|
||||
|
||||
RsvEventDispatcher::init( new RsvWordPressEventBus() );
|
||||
|
||||
RsvGoogleCalendarListener::register();
|
||||
RsvEmailListener::register();
|
||||
|
||||
// Shared element registry — consumed via `global $rsv_form_registry` by the
|
||||
// form processor, HTML renderer, and the form-admin pages.
|
||||
$rsv_form_registry = new RsvFormElementRegistry();
|
||||
$rsv_form_registry->register( 'input-text', new RsvTextFieldElementHandler() );
|
||||
$rsv_form_registry->register( 'button', new RsvButtonElementHandler() );
|
||||
$rsv_form_registry->register( 'reservation', new RsvFormReservationElementHandler() );
|
||||
$rsv_form_registry->register( 'output-reservation-summary', new RsvReservationSummaryElementHandler() );
|
||||
}
|
||||
|
||||
add_action( 'plugins_loaded', 'rsv_bootstrap' );
|
||||
|
||||
add_action( 'admin_menu', 'rsv_admin_menu_definition' );
|
||||
add_action( 'init', 'rsv_register_block' );
|
||||
add_action( 'enqueue_block_assets', 'rsv_enqueue_assets' );
|
||||
add_action( 'admin_enqueue_scripts', 'rsv_enqueue_admin_assets' );
|
||||
add_action( 'wp_dashboard_setup', 'rsv_add_dashboard_widget' );
|
||||
add_action( 'rest_api_init', 'rsv_define_rest_api' );
|
||||
|
||||
/**
|
||||
* Registers the block using the metadata loaded from the `block.json` file.
|
||||
* Behind the scenes, it registers also all assets so they can be enqueued
|
||||
* through the block editor in the corresponding context.
|
||||
*
|
||||
* @see https://developer.wordpress.org/reference/functions/register_block_type/
|
||||
*/
|
||||
function rsv_register_block() {
|
||||
register_block_type( __DIR__ . '/build' );
|
||||
}
|
||||
|
||||
function rsv_add_dashboard_widget() {
|
||||
wp_add_dashboard_widget(
|
||||
'rsv_pending_reservations_widget',
|
||||
'Pending Reservation Requests',
|
||||
'rsv_pending_reservations_widget_render'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the "Pending Reservation Requests" dashboard widget.
|
||||
*/
|
||||
function rsv_pending_reservations_widget_render(): void {
|
||||
$url = admin_url( 'admin.php?page=reservations-settings' );
|
||||
echo '<p>' . esc_html__( 'Manage and review reservation requests from the Reservations admin page.', 'reservair' ) . '</p>';
|
||||
echo '<p><a href="' . esc_url( $url ) . '" class="button button-primary">'
|
||||
. esc_html__( 'Open Reservations', 'reservair' ) . '</a></p>';
|
||||
}
|
||||
|
||||
function rsv_google_oauth_callback($request) {
|
||||
$code = sanitize_text_field($request->get_param('code'));
|
||||
|
||||
if (!$code) {
|
||||
return new WP_REST_Response(['error' => 'No code received'], 400);
|
||||
}
|
||||
|
||||
$service = new RsvGoogleCalendarService();
|
||||
if ($service->exchange_code($code)) {
|
||||
$service->register_webhook();
|
||||
wp_redirect(admin_url('admin.php?page=rsv-google-calendar&connected=1'));
|
||||
exit;
|
||||
}
|
||||
|
||||
return new WP_REST_Response(['error' => 'Token exchange failed'], 500);
|
||||
}
|
||||
|
||||
function rsv_google_calendar_webhook(WP_REST_Request $request): WP_REST_Response {
|
||||
$headers = $request->get_headers();
|
||||
|
||||
$channel_id = $headers['x_goog_channel_id'][0] ?? '';
|
||||
$resource_state = $headers['x_goog_resource_state'][0] ?? '';
|
||||
|
||||
if ($channel_id !== get_option('rsv_google_webhook_channel_id')) {
|
||||
return new WP_REST_Response(['error' => 'Invalid channel'], 400);
|
||||
}
|
||||
|
||||
// Google sends a 'sync' notification when the webhook is first registered.
|
||||
if ($resource_state === 'sync') {
|
||||
return new WP_REST_Response(['status' => 'ok'], 200);
|
||||
}
|
||||
|
||||
$gcal = new RsvGoogleCalendarService();
|
||||
$actions = $gcal->process_changes();
|
||||
$service = new RsvTimetableReservationService();
|
||||
|
||||
foreach ($actions as $action) {
|
||||
try {
|
||||
if ($action['action'] === 'accept') {
|
||||
$service->accept_by_reservation_id($action['reservation_id']);
|
||||
} else {
|
||||
$service->refuse_by_reservation_id($action['reservation_id']);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
error_log('Google Calendar sync [' . $action['action'] . ' #' . $action['reservation_id'] . ']: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return new WP_REST_Response(['status' => 'ok'], 200);
|
||||
}
|
||||
Reference in New Issue
Block a user