File: /home/mbkashyap/domains/mbkashyap.com/public_html/wp-content/plugins/bizmaster-core/ptbook/book.php
<?php
/*
Plugin Name: AstroBook - Appointment Booking for Astrology
Plugin URI: https://your-astrology-website.com
Description: Complete appointment booking solution for astrology websites with Razorpay payments and admin management.
Version: 2.0.0
Author: Simar
Author URI: https://your-website.com
License: GPL-2.0+
Text Domain: astrobook
*/
defined('ABSPATH') || exit;
class AstroBook_Plugin {
private static $instance = null;
public $version = '1.0.0';
// Database tables
public $table_availability;
public $table_appointments;
public $table_coupons;
public static function instance() {
if (is_null(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
public function __construct() {
global $wpdb;
$this->table_availability = $wpdb->prefix . 'astrobook_availability';
$this->table_appointments = $wpdb->prefix . 'astrobook_appointments';
$this->table_coupons = $wpdb->prefix . 'astrobook_coupons';
// Activation and deactivation hooks
register_activation_hook(__FILE__, array($this, 'activate'));
register_deactivation_hook(__FILE__, array($this, 'deactivate'));
// Initialize plugin
add_action('plugins_loaded', array($this, 'init_plugin'));
}
public function activate() {
$this->create_tables();
$this->create_default_options();
}
public function deactivate() {
// Clean up if needed
}
public function init_plugin() {
// Set up admin menu
add_action('admin_menu', array($this, 'create_admin_menu'));
// Enqueue scripts and styles
add_action('admin_enqueue_scripts', array($this, 'admin_scripts'));
add_action('wp_enqueue_scripts', array($this, 'frontend_scripts'));
// AJAX handlers
add_action('wp_ajax_astrobook_save_availability', array($this, 'save_availability'));
add_action('wp_ajax_astrobook_get_availability', array($this, 'get_availability'));
add_action('wp_ajax_astrobook_apply_coupon', array($this, 'apply_coupon'));
add_action('wp_ajax_astrobook_create_order', array($this, 'create_order'));
add_action('wp_ajax_astrobook_verify_payment', array($this, 'verify_payment'));
add_action('wp_ajax_nopriv_astrobook_apply_coupon', array($this, 'apply_coupon'));
add_action('wp_ajax_nopriv_astrobook_create_order', array($this, 'create_order'));
add_action('wp_ajax_nopriv_astrobook_verify_payment', array($this, 'verify_payment'));
add_action('wp_ajax_astrobook_get_available_slots', array($this, 'get_available_slots_ajax'));
add_action('wp_ajax_nopriv_astrobook_get_available_slots', array($this, 'get_available_slots_ajax'));
// Shortcodes
add_shortcode('astrobook_calendar', array($this, 'calendar_shortcode'));
add_shortcode('astrobook_booking_form', array($this, 'booking_form_shortcode'));
}
public function create_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
// Availability table
$sql = "CREATE TABLE {$this->table_availability} (
id mediumint(9) NOT NULL AUTO_INCREMENT,
astrologer_id mediumint(9) NOT NULL DEFAULT 0,
day_of_week tinyint(1) NOT NULL,
start_time time NOT NULL,
end_time time NOT NULL,
is_active tinyint(1) NOT NULL DEFAULT 1,
PRIMARY KEY (id)
) $charset_collate;";
dbDelta($sql);
// Appointments table
$sql = "CREATE TABLE {$this->table_appointments} (
id mediumint(9) NOT NULL AUTO_INCREMENT,
user_id bigint(20) NOT NULL,
astrologer_id mediumint(9) NOT NULL DEFAULT 0,
appointment_date date NOT NULL,
start_time time NOT NULL,
end_time time NOT NULL,
service_type varchar(100) NOT NULL,
price decimal(10,2) NOT NULL,
coupon_code varchar(50) DEFAULT NULL,
discount decimal(10,2) DEFAULT 0.00,
total_price decimal(10,2) NOT NULL,
status varchar(20) NOT NULL DEFAULT 'pending',
payment_id varchar(255) DEFAULT NULL,
created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) $charset_collate;";
dbDelta($sql);
// Coupons table
$sql = "CREATE TABLE {$this->table_coupons} (
id mediumint(9) NOT NULL AUTO_INCREMENT,
code varchar(50) NOT NULL,
discount_type varchar(10) NOT NULL COMMENT 'percent or fixed',
discount_value decimal(10,2) NOT NULL,
max_uses mediumint(9) DEFAULT NULL,
used_count mediumint(9) NOT NULL DEFAULT 0,
start_date date DEFAULT NULL,
end_date date DEFAULT NULL,
is_active tinyint(1) NOT NULL DEFAULT 1,
PRIMARY KEY (id),
UNIQUE KEY code (code)
) $charset_collate;";
dbDelta($sql);
}
public function create_default_options() {
// Time slots
if (!get_option('astrobook_time_slots')) {
update_option('astrobook_time_slots', ['30', '60']);
}
// Services
if (!get_option('astrobook_services')) {
$default_services = [
['name' => 'Birth Chart Reading', 'price' => 1500],
['name' => 'Career Prediction', 'price' => 1200],
['name' => 'Relationship Analysis', 'price' => 1800]
];
update_option('astrobook_services', $default_services);
}
// Notification settings
if (!get_option('astrobook_admin_email')) {
update_option('astrobook_admin_email', get_option('admin_email'));
}
if (!get_option('astrobook_client_email_subject')) {
update_option('astrobook_client_email_subject', 'Your Astrology Appointment Confirmation');
}
if (!get_option('astrobook_client_email_body')) {
update_option('astrobook_client_email_body', "Hello {name},\n\nYour appointment is confirmed for {date} at {time}.\n\nService: {service}\nAmount: {price}\n\nThank you!");
}
if (!get_option('astrobook_admin_email_subject')) {
update_option('astrobook_admin_email_subject', 'New Appointment Booking');
}
if (!get_option('astrobook_admin_email_body')) {
update_option('astrobook_admin_email_body', "Hello,\n\nYou have a new appointment booking:\n\nClient: {name}\nEmail: {email}\nDate: {date}\nTime: {time}\nService: {service}\nAmount: {price}\nPayment ID: {payment_id}");
}
}
public function create_admin_menu() {
add_menu_page(
__('AstroBook', 'astrobook'),
__('AstroBook', 'astrobook'),
'manage_options',
'astrobook',
array($this, 'admin_dashboard'),
'dashicons-calendar-alt',
30
);
add_submenu_page(
'astrobook',
__('Dashboard', 'astrobook'),
__('Dashboard', 'astrobook'),
'manage_options',
'astrobook',
array($this, 'admin_dashboard')
);
add_submenu_page(
'astrobook',
__('Availability', 'astrobook'),
__('Availability', 'astrobook'),
'manage_options',
'astrobook-availability',
array($this, 'admin_availability')
);
add_submenu_page(
'astrobook',
__('Appointments', 'astrobook'),
__('Appointments', 'astrobook'),
'manage_options',
'astrobook-appointments',
array($this, 'admin_appointments')
);
add_submenu_page(
'astrobook',
__('Coupons', 'astrobook'),
__('Coupons', 'astrobook'),
'manage_options',
'astrobook-coupons',
array($this, 'admin_coupons')
);
add_submenu_page(
'astrobook',
__('Settings', 'astrobook'),
__('Settings', 'astrobook'),
'manage_options',
'astrobook-settings',
array($this, 'admin_settings')
);
}
public function admin_scripts($hook) {
if (strpos($hook, 'astrobook') === false) return;
// FullCalendar from CDN
wp_enqueue_style('fullcalendar-core', 'https://cdn.jsdelivr.net/npm/fullcalendar@5.10.1/main.min.css', array(), '5.10.1');
wp_enqueue_script('fullcalendar-core', 'https://cdn.jsdelivr.net/npm/fullcalendar@5.10.1/main.min.js', array('jquery'), '5.10.1', true);
wp_enqueue_script('fullcalendar-interaction', 'https://cdn.jsdelivr.net/npm/fullcalendar@5.10.1/interaction/main.min.js', array('fullcalendar-core'), '5.10.1', true);
wp_enqueue_script('fullcalendar-daygrid', 'https://cdn.jsdelivr.net/npm/fullcalendar@5.10.1/daygrid/main.min.js', array('fullcalendar-core'), '5.10.1', true);
wp_enqueue_script('fullcalendar-timegrid', 'https://cdn.jsdelivr.net/npm/fullcalendar@5.10.1/timegrid/main.min.js', array('fullcalendar-core'), '5.10.1', true);
// Plugin-specific assets
wp_enqueue_style('astrobook-admin', plugin_dir_url(__FILE__) . 'assets/css/admin.css', array(), $this->version);
wp_enqueue_script('astrobook-admin', plugin_dir_url(__FILE__) . 'assets/js/admin.js', array('jquery', 'fullcalendar-core', 'fullcalendar-interaction', 'fullcalendar-daygrid', 'fullcalendar-timegrid'), $this->version, true);
// Localize script data
wp_localize_script('astrobook-admin', 'astrobook_admin', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('astrobook_admin_nonce'),
'time_format' => get_option('time_format', 'g:i a'),
'default_start' => '09:00:00',
'default_end' => '18:00:00',
'time_slots' => get_option('astrobook_time_slots', ['30']),
'colors' => array(
'available' => '#4caf50',
'booked' => '#f44336',
'selected' => '#2196f3',
'admin' => '#ff9800'
)
));
}
public function frontend_scripts() {
global $post;
if (!is_a($post, 'WP_Post')) return;
if (has_shortcode($post->post_content, 'astrobook_calendar') ||
has_shortcode($post->post_content, 'astrobook_booking_form')) {
// FullCalendar from CDN
wp_enqueue_style('fullcalendar-core', 'https://cdn.jsdelivr.net/npm/fullcalendar@5.10.1/main.min.css', array(), '5.10.1');
wp_enqueue_script('fullcalendar-core', 'https://cdn.jsdelivr.net/npm/fullcalendar@5.10.1/main.min.js', array('jquery'), '5.10.1', true);
wp_enqueue_script('fullcalendar-interaction', 'https://cdn.jsdelivr.net/npm/fullcalendar@5.10.1/interaction/main.min.js', array('fullcalendar-core'), '5.10.1', true);
wp_enqueue_script('fullcalendar-daygrid', 'https://cdn.jsdelivr.net/npm/fullcalendar@5.10.1/daygrid/main.min.js', array('fullcalendar-core'), '5.10.1', true);
wp_enqueue_script('fullcalendar-timegrid', 'https://cdn.jsdelivr.net/npm/fullcalendar@5.10.1/timegrid/main.min.js', array('fullcalendar-core'), '5.10.1', true);
// Razorpay
wp_enqueue_script('razorpay-checkout', 'https://checkout.razorpay.com/v1/checkout.js', array(), null, true);
// Plugin-specific assets
wp_enqueue_style('astrobook-frontend', plugin_dir_url(__FILE__) . 'assets/css/frontend.css', array(), $this->version);
wp_enqueue_script('astrobook-frontend', plugin_dir_url(__FILE__) . 'assets/js/frontend.js', array('jquery', 'fullcalendar-core', 'fullcalendar-interaction', 'fullcalendar-daygrid', 'fullcalendar-timegrid', 'razorpay-checkout'), $this->version, true);
// Localize script data
wp_localize_script('astrobook-frontend', 'astrobook_frontend', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('astrobook_frontend_nonce'),
'time_format' => get_option('time_format', 'g:i a'),
'razorpay_key' => get_option('astrobook_razorpay_key'),
'currency' => 'INR',
'currency_symbol' => '₹',
'colors' => array(
'available' => '#4caf50',
'booked' => '#f44336',
'selected' => '#2196f3'
)
));
}
}
// Admin pages
public function admin_dashboard() {
$this->include_template('admin/dashboard');
}
public function admin_availability() {
$this->include_template('admin/availability');
}
public function admin_appointments() {
$this->include_template('admin/appointments');
}
public function admin_coupons() {
$this->include_template('admin/coupons');
}
public function admin_settings() {
$this->include_template('admin/settings');
}
// Shortcodes
public function calendar_shortcode() {
ob_start();
$this->include_template('frontend/calendar');
return ob_get_clean();
}
public function booking_form_shortcode() {
ob_start();
$this->include_template('frontend/booking-form');
return ob_get_clean();
}
// AJAX handlers
public function save_availability() {
check_ajax_referer('astrobook_admin_nonce', 'nonce');
global $wpdb;
$availability = isset($_POST['availability']) ? json_decode(stripslashes($_POST['availability']), true) : array();
$astrologer_id = 0;
// Clear existing availability
$wpdb->delete($this->table_availability, array('astrologer_id' => $astrologer_id));
// Insert new availability
foreach ($availability as $day => $slots) {
foreach ($slots as $slot) {
$wpdb->insert($this->table_availability, array(
'astrologer_id' => $astrologer_id,
'day_of_week' => $day,
'start_time' => $slot['start'],
'end_time' => $slot['end'],
'is_active' => 1
));
}
}
wp_send_json_success();
}
public function get_availability() {
check_ajax_referer('astrobook_admin_nonce', 'nonce');
global $wpdb;
$astrologer_id = 0;
$availability = $wpdb->get_results($wpdb->prepare(
"SELECT day_of_week, start_time, end_time FROM {$this->table_availability}
WHERE astrologer_id = %d AND is_active = 1",
$astrologer_id
), ARRAY_A);
$formatted = array();
foreach ($availability as $slot) {
$formatted[$slot['day_of_week']][] = array(
'start' => $slot['start_time'],
'end' => $slot['end_time']
);
}
wp_send_json_success($formatted);
}
public function get_available_slots($date) {
global $wpdb;
// Get day of week (0=Sunday, 6=Saturday)
$day_of_week = date('w', strtotime($date));
// Get available slots for this day
$available_slots = $wpdb->get_results($wpdb->prepare(
"SELECT start_time, end_time
FROM {$this->table_availability}
WHERE day_of_week = %d AND is_active = 1",
$day_of_week
));
// Get booked appointments for this date
$booked_appointments = $wpdb->get_results($wpdb->prepare(
"SELECT start_time, end_time
FROM {$this->table_appointments}
WHERE appointment_date = %s AND status != 'cancelled'",
$date
));
// Generate time slots
$time_slots = [];
$time_slot_duration = 30; // minutes
foreach ($available_slots as $slot) {
$start = strtotime($slot->start_time);
$end = strtotime($slot->end_time);
while ($start < $end) {
$slot_start = date('H:i:s', $start);
$slot_end = date('H:i:s', $start + ($time_slot_duration * 60));
// Check if slot is available
$is_available = true;
foreach ($booked_appointments as $appointment) {
if ($slot_start >= $appointment->start_time && $slot_start < $appointment->end_time) {
$is_available = false;
break;
}
}
if ($is_available && ($start + ($time_slot_duration * 60) <= $end)) {
$time_slots[] = [
'start' => $slot_start,
'end' => $slot_end,
'formatted' => date(get_option('time_format'), strtotime($slot_start)) . ' - ' . date(get_option('time_format'), strtotime($slot_end))
];
}
$start += $time_slot_duration * 60;
}
}
return $time_slots;
}
public function get_available_slots_ajax() {
check_ajax_referer('astrobook_frontend_nonce', 'nonce');
$date = isset($_POST['date']) ? sanitize_text_field($_POST['date']) : '';
if (empty($date)) {
wp_send_json_error(array('message' => 'Invalid date'));
}
$slots = $this->get_available_slots($date);
wp_send_json_success($slots);
}
public function apply_coupon() {
check_ajax_referer('astrobook_frontend_nonce', 'nonce');
$coupon_code = isset($_POST['coupon_code']) ? sanitize_text_field($_POST['coupon_code']) : '';
$total = isset($_POST['total']) ? floatval($_POST['total']) : 0;
global $wpdb;
$coupon = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM {$this->table_coupons} WHERE code = %s AND is_active = 1",
$coupon_code
));
if (!$coupon) {
wp_send_json_error(array('message' => __('Invalid coupon code.', 'astrobook')));
}
// Check validity
$now = current_time('Y-m-d');
if ($coupon->start_date && $coupon->start_date > $now) {
wp_send_json_error(array('message' => __('Coupon not yet valid.', 'astrobook')));
}
if ($coupon->end_date && $coupon->end_date < $now) {
wp_send_json_error(array('message' => __('Coupon has expired.', 'astrobook')));
}
if ($coupon->max_uses && $coupon->used_count >= $coupon->max_uses) {
wp_send_json_error(array('message' => __('Coupon usage limit reached.', 'astrobook')));
}
// Apply discount
$discount = 0;
if ($coupon->discount_type == 'percent') {
$discount = ($coupon->discount_value / 100) * $total;
} else {
$discount = $coupon->discount_value;
}
// Ensure discount doesn't exceed total
if ($discount > $total) {
$discount = $total;
}
$new_total = $total - $discount;
wp_send_json_success(array(
'discount' => $discount,
'new_total' => $new_total,
'coupon_id' => $coupon->id
));
}
public function create_order() {
check_ajax_referer('astrobook_frontend_nonce', 'nonce');
$api_key = get_option('astrobook_razorpay_key');
$api_secret = get_option('astrobook_razorpay_secret');
if (empty($api_key) {
wp_send_json_error(array('message' => 'Razorpay API key is not configured'));
}
// Include Razorpay SDK
if (!class_exists('Razorpay\Api\Api')) {
require_once __DIR__ . '/includes/razorpay-php/Razorpay.php';
}
$amount = isset($_POST['amount']) ? floatval($_POST['amount']) * 100 : 0; // in paise
$appointment_data = isset($_POST['appointment_data']) ? $_POST['appointment_data'] : array();
try {
$api = new Razorpay\Api\Api($api_key, $api_secret);
$order = $api->order->create(array(
'receipt' => 'order_rcpt_' . time(),
'amount' => $amount,
'currency' => 'INR'
));
wp_send_json_success(array(
'order_id' => $order->id,
'amount' => $amount,
'appointment_data' => $appointment_data
));
} catch (Exception $e) {
wp_send_json_error(array('message' => $e->getMessage()));
}
}
public function verify_payment() {
check_ajax_referer('astrobook_frontend_nonce', 'nonce');
$api_key = get_option('astrobook_razorpay_key');
$api_secret = get_option('astrobook_razorpay_secret');
// Include Razorpay SDK
if (!class_exists('Razorpay\Api\Api')) {
require_once __DIR__ . '/includes/razorpay-php/Razorpay.php';
}
$api = new Razorpay\Api\Api($api_key, $api_secret);
$razorpay_order_id = isset($_POST['razorpay_order_id']) ? sanitize_text_field($_POST['razorpay_order_id']) : '';
$razorpay_payment_id = isset($_POST['razorpay_payment_id']) ? sanitize_text_field($_POST['razorpay_payment_id']) : '';
$razorpay_signature = isset($_POST['razorpay_signature']) ? sanitize_text_field($_POST['razorpay_signature']) : '';
$appointment_data = isset($_POST['appointment_data']) ? $_POST['appointment_data'] : array();
try {
$attributes = array(
'razorpay_order_id' => $razorpay_order_id,
'razorpay_payment_id' => $razorpay_payment_id,
'razorpay_signature' => $razorpay_signature
);
$api->utility->verifyPaymentSignature($attributes);
// Payment successful, create appointment
$appointment_id = $this->create_appointment($appointment_data, $razorpay_payment_id);
if ($appointment_id) {
// Send notifications
$this->send_notification($appointment_id, 'client');
$this->send_notification($appointment_id, 'admin');
wp_send_json_success(array('appointment_id' => $appointment_id));
} else {
wp_send_json_error(array('message' => __('Failed to create appointment.', 'astrobook')));
}
} catch (Exception $e) {
wp_send_json_error(array('message' => $e->getMessage()));
}
}
public function create_appointment($data, $payment_id) {
global $wpdb;
$user_id = get_current_user_id();
$user = $user_id ? get_userdata($user_id) : null;
$appointment_data = array(
'user_id' => $user_id,
'astrologer_id' => 0,
'appointment_date' => $data['date'],
'start_time' => $data['start_time'],
'end_time' => $data['end_time'],
'service_type' => $data['service'],
'price' => $data['price'],
'coupon_code' => $data['coupon_code'],
'discount' => $data['discount'],
'total_price' => $data['total'],
'status' => 'confirmed',
'payment_id' => $payment_id,
'created_at' => current_time('mysql')
);
$wpdb->insert($this->table_appointments, $appointment_data);
return $wpdb->insert_id;
}
public function send_notification($appointment_id, $recipient = 'client') {
global $wpdb;
$appointment = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM {$this->table_appointments} WHERE id = %d",
$appointment_id
));
if (!$appointment) return false;
$user = get_userdata($appointment->user_id);
$admin_email = get_option('admin_email');
$astrobook_admin_email = get_option('astrobook_admin_email', $admin_email);
if ($recipient == 'client') {
$to = $user->user_email;
$subject = get_option('astrobook_client_email_subject', 'Your Astrology Appointment Confirmation');
$body = get_option('astrobook_client_email_body');
} else {
$to = $astrobook_admin_email;
$subject = get_option('astrobook_admin_email_subject', 'New Appointment Booking');
$body = get_option('astrobook_admin_email_body');
}
// Replace placeholders
$replacements = array(
'{name}' => $user->display_name,
'{email}' => $user->user_email,
'{date}' => date_i18n(get_option('date_format'), strtotime($appointment->appointment_date)),
'{time}' => date_i18n(get_option('time_format'), strtotime($appointment->start_time)),
'{service}' => $appointment->service_type,
'{price}' => wc_price($appointment->total_price),
'{payment_id}' => $appointment->payment_id
);
$body = str_replace(array_keys($replacements), array_values($replacements), $body);
// Send email
$headers = array('Content-Type: text/html; charset=UTF-8');
return wp_mail($to, $subject, $body, $headers);
}
// Helper methods
private function include_template($template) {
$template_path = plugin_dir_path(__FILE__) . 'templates/' . $template . '.php';
if (file_exists($template_path)) {
include $template_path;
} else {
echo '<div class="error"><p>Template not found: ' . esc_html($template_path) . '</p></div>';
}
}
private function create_assets_directory() {
$assets_dir = plugin_dir_path(__FILE__) . 'assets';
if (!is_dir($assets_dir)) {
wp_mkdir_p($assets_dir);
wp_mkdir_p($assets_dir . '/css');
wp_mkdir_p($assets_dir . '/js');
}
}
private function create_default_assets() {
$this->create_assets_directory();
// Create admin CSS
$admin_css = <<<CSS
/* Admin CSS */
.astrobook-dashboard .astrobook-stats {
display: flex;
gap: 20px;
margin-bottom: 30px;
}
.astrobook-dashboard .stat-box {
background: #fff;
border: 1px solid #ccd0d4;
border-radius: 4px;
padding: 20px;
flex: 1;
text-align: center;
box-shadow: 0 1px 1px rgba(0,0,0,0.04);
}
.astrobook-dashboard .stat-box h3 {
margin-top: 0;
color: #72777c;
}
.astrobook-dashboard .stat-box p {
font-size: 2em;
font-weight: bold;
margin: 10px 0 0;
color: #0073aa;
}
.astrobook-availability #astrobook-availability-calendar {
max-width: 900px;
margin-bottom: 20px;
}
.astrobook-coupons .astrobook-coupon-form {
background: #fff;
padding: 20px;
margin-bottom: 30px;
border: 1px solid #ccd0d4;
border-radius: 4px;
box-shadow: 0 1px 1px rgba(0,0,0,0.04);
}
.astrobook-settings .form-table textarea.large-text {
min-height: 150px;
}
.status-confirmed {
color: #4caf50;
font-weight: bold;
}
.status-pending {
color: #ff9800;
font-weight: bold;
}
.status-active {
color: #4caf50;
font-weight: bold;
}
.button-danger {
background: #f44336;
border-color: #f44336;
color: white;
}
.button-danger:hover {
background: #d32f2f;
border-color: #d32f2f;
color: white;
}
.astrobook-service {
display: flex;
gap: 10px;
margin-bottom: 10px;
align-items: center;
}
.astrobook-service input[type="text"] {
flex: 2;
}
.astrobook-service input[type="number"] {
flex: 1;
}
CSS;
file_put_contents(plugin_dir_path(__FILE__) . 'assets/css/admin.css', $admin_css);
// Create frontend CSS
$frontend_css = <<<CSS
/* Frontend CSS */
.astrobook-frontend-calendar {
margin-bottom: 30px;
background: white;
padding: 20px;
border-radius: 5px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.astrobook-booking-form {
background: #f8f9fa;
padding: 20px;
border-radius: 5px;
margin-top: 20px;
}
.astrobook-booking-form .form-group {
margin-bottom: 15px;
}
.astrobook-booking-form label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
.astrobook-booking-form input,
.astrobook-booking-form select {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
.astrobook-booking-form button {
background: #0073aa;
color: white;
border: none;
padding: 10px 15px;
border-radius: 4px;
cursor: pointer;
}
.astrobook-booking-form button:hover {
background: #005177;
}
#astrobook-coupon-message {
margin-top: 5px;
font-style: italic;
}
#astrobook-slots-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 10px;
margin-top: 15px;
}
.slot-button {
background: #4caf50;
color: white;
border: none;
padding: 10px;
border-radius: 4px;
cursor: pointer;
text-align: center;
}
.slot-button:hover {
background: #388e3c;
}
.slot-button.selected {
background: #2196f3;
border: 2px solid #0d47a1;
}
CSS;
file_put_contents(plugin_dir_path(__FILE__) . 'assets/css/frontend.css', $frontend_css);
// Create admin JS
$admin_js = <<<JS
jQuery(document).ready(function($) {
var calendarEl = document.getElementById('astrobook-availability-calendar');
if (calendarEl) {
var calendar = new FullCalendar.Calendar(calendarEl, {
plugins: ['interaction', 'dayGrid', 'timeGrid'],
header: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay'
},
defaultView: 'timeGridWeek',
editable: true,
selectable: true,
selectMirror: true,
allDaySlot: false,
slotDuration: '00:15:00',
slotLabelInterval: '01:00:00',
events: function(fetchInfo, successCallback, failureCallback) {
$.ajax({
url: astrobook_admin.ajax_url,
type: 'POST',
data: {
action: 'astrobook_get_availability',
nonce: astrobook_admin.nonce
},
success: function(response) {
if (response.success) {
var events = [];
var availability = response.data;
// Convert availability to events
for (var day in availability) {
if (availability.hasOwnProperty(day)) {
availability[day].forEach(function(slot) {
events.push({
daysOfWeek: [day],
startTime: slot.start,
endTime: slot.end,
color: astrobook_admin.colors.available,
rendering: 'background'
});
});
}
}
successCallback(events);
}
}
});
},
select: function(selectionInfo) {
// Only allow background selection for availability
return false;
},
dateClick: function(info) {
// Handle date click for availability
}
});
calendar.render();
// Save availability
$('#astrobook-save-availability').on('click', function() {
var availability = {};
// Get all background events
var events = calendar.getEvents().filter(function(event) {
return event.rendering === 'background';
});
events.forEach(function(event) {
var day = event.start.getUTCDay();
if (!availability[day]) availability[day] = [];
availability[day].push({
start: $.fullCalendar.formatDate(event.start, 'HH:mm:ss'),
end: $.fullCalendar.formatDate(event.end, 'HH:mm:ss')
});
});
$.ajax({
url: astrobook_admin.ajax_url,
type: 'POST',
data: {
action: 'astrobook_save_availability',
nonce: astrobook_admin.nonce,
availability: JSON.stringify(availability)
},
success: function(response) {
if (response.success) {
alert('Availability saved successfully!');
}
}
});
});
}
});
JS;
file_put_contents(plugin_dir_path(__FILE__) . 'assets/js/admin.js', $admin_js);
// Create frontend JS
$frontend_js = <<<JS
jQuery(document).ready(function($) {
var calendarEl = document.getElementById('astrobook-calendar');
var selectedDate = null;
var selectedSlot = null;
var servicePrice = 0;
var discount = 0;
var couponId = null;
if (calendarEl) {
var calendar = new FullCalendar.Calendar(calendarEl, {
plugins: ['interaction', 'dayGrid', 'timeGrid'],
header: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay'
},
initialView: get_option('astrobook_calendar_view', 'timeGridWeek'),
editable: false,
selectable: true,
allDaySlot: false,
slotDuration: '00:15:00',
slotLabelInterval: '01:00:00',
dateClick: function(info) {
selectedDate = info.dateStr;
$('#astrobook-time-slots').show();
$('#astrobook-slots-container').html('<p>Loading available slots...</p>');
$.ajax({
url: astrobook_frontend.ajax_url,
type: 'POST',
data: {
action: 'astrobook_get_available_slots',
nonce: astrobook_frontend.nonce,
date: selectedDate
},
success: function(response) {
if (response.success) {
var slotsHtml = '';
if (response.data.length > 0) {
response.data.forEach(function(slot) {
slotsHtml += '<button type="button" class="slot-button" data-start="' + slot.start + '" data-end="' + slot.end + '">' + slot.formatted + '</button>';
});
} else {
slotsHtml = '<p>No available slots for this date.</p>';
}
$('#astrobook-slots-container').html(slotsHtml);
}
}
});
},
eventClick: function(info) {
// Handle event click
}
});
calendar.render();
}
// Slot selection
$(document).on('click', '.slot-button', function() {
$('.slot-button').removeClass('selected');
$(this).addClass('selected');
var startTime = $(this).data('start');
var endTime = $(this).data('end');
// Show booking form
$('.astrobook-booking-form').show();
$('#astrobook-selected-slot').text(
'Selected Slot: ' +
new Date(selectedDate).toLocaleDateString() + ' ' +
new Date('1970-01-01T' + startTime + 'Z').toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) + ' - ' +
new Date('1970-01-01T' + endTime + 'Z').toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
);
$('#astrobook-appointment-date').val(selectedDate);
$('#astrobook-appointment-start-time').val(startTime);
$('#astrobook-appointment-end-time').val(endTime);
});
// Service selection
$('#astrobook-service').on('change', function() {
servicePrice = parseFloat($(this).find(':selected').data('price')) || 0;
updatePriceDisplay();
});
// Apply coupon
$('#astrobook-apply-coupon').on('click', function() {
var couponCode = $('#astrobook-coupon').val();
if (!couponCode) return;
$.ajax({
url: astrobook_frontend.ajax_url,
type: 'POST',
data: {
action: 'astrobook_apply_coupon',
nonce: astrobook_frontend.nonce,
coupon_code: couponCode,
total: servicePrice
},
success: function(response) {
if (response.success) {
discount = response.data.discount;
couponId = response.data.coupon_id;
$('#astrobook-coupon-message').text('Coupon applied successfully!').css('color', 'green');
updatePriceDisplay();
} else {
discount = 0;
couponId = null;
$('#astrobook-coupon-message').text(response.data.message).css('color', 'red');
updatePriceDisplay();
}
}
});
});
// Update price display
function updatePriceDisplay() {
var total = servicePrice - discount;
$('#astrobook-price-display').text('₹' + servicePrice.toFixed(2));
$('#astrobook-discount-display').text('₹' + discount.toFixed(2));
$('#astrobook-total-display').text('₹' + total.toFixed(2));
}
// Form submission
$('#astrobook-appointment-form').on('submit', function(e) {
e.preventDefault();
var service = $('#astrobook-service').val();
if (!service) {
alert('Please select a service');
return;
}
var appointmentData = {
date: $('#astrobook-appointment-date').val(),
start_time: $('#astrobook-appointment-start-time').val(),
end_time: $('#astrobook-appointment-end-time').val(),
service: service,
price: servicePrice,
coupon_code: $('#astrobook-coupon').val() || '',
discount: discount,
total: servicePrice - discount
};
// Create Razorpay order
$.ajax({
url: astrobook_frontend.ajax_url,
type: 'POST',
data: {
action: 'astrobook_create_order',
nonce: astrobook_frontend.nonce,
amount: appointmentData.total,
appointment_data: appointmentData
},
success: function(response) {
if (response.success) {
var order = response.data;
var options = {
key: astrobook_frontend.razorpay_key,
amount: order.amount,
currency: 'INR',
name: 'Astrology Consultation',
description: appointmentData.service,
order_id: order.order_id,
handler: function(razorpayResponse) {
// Verify payment
$.ajax({
url: astrobook_frontend.ajax_url,
type: 'POST',
data: {
action: 'astrobook_verify_payment',
nonce: astrobook_frontend.nonce,
razorpay_order_id: razorpayResponse.razorpay_order_id,
razorpay_payment_id: razorpayResponse.razorpay_payment_id,
razorpay_signature: razorpayResponse.razorpay_signature,
appointment_data: order.appointment_data
},
success: function(verifyResponse) {
if (verifyResponse.success) {
alert('Booking confirmed! Your appointment ID: ' + verifyResponse.data.appointment_id);
location.reload();
} else {
alert('Payment verification failed: ' + verifyResponse.data.message);
}
}
});
},
prefill: {
name: '',
email: '',
contact: ''
},
theme: {
color: '#F37254'
}
};
var rzp = new Razorpay(options);
rzp.open();
} else {
alert('Error creating order: ' + response.data.message);
}
}
});
});
});
JS;
file_put_contents(plugin_dir_path(__FILE__) . 'assets/js/frontend.js', $frontend_js);
}
private function create_template_files() {
$templates_dir = plugin_dir_path(__FILE__) . 'templates';
if (!is_dir($templates_dir)) {
wp_mkdir_p($templates_dir);
wp_mkdir_p($templates_dir . '/admin');
wp_mkdir_p($templates_dir . '/frontend');
}
// Create admin templates
$admin_templates = [
'dashboard' => '<div class="wrap astrobook-dashboard">
<h1><?php esc_html_e("AstroBook Dashboard", "astrobook"); ?></h1>
<div class="astrobook-stats">
<div class="stat-box">
<h3><?php esc_html_e("Today\'s Appointments", "astrobook"); ?></h3>
<p>5</p>
</div>
<div class="stat-box">
<h3><?php esc_html_e("Upcoming Appointments", "astrobook"); ?></h3>
<p>12</p>
</div>
<div class="stat-box">
<h3><?php esc_html_e("Pending Payments", "astrobook"); ?></h3>
<p>2</p>
</div>
</div>
<div class="astrobook-recent-appointments">
<h2><?php esc_html_e("Recent Appointments", "astrobook"); ?></h2>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th><?php esc_html_e("ID", "astrobook"); ?></th>
<th><?php esc_html_e("Client", "astrobook"); ?></th>
<th><?php esc_html_e("Date & Time", "astrobook"); ?></th>
<th><?php esc_html_e("Service", "astrobook"); ?></th>
<th><?php esc_html_e("Amount", "astrobook"); ?></th>
<th><?php esc_html_e("Status", "astrobook"); ?></th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>John Doe</td>
<td>June 20, 2023 10:00 AM</td>
<td>Birth Chart Reading</td>
<td>₹1500.00</td>
<td>Confirmed</td>
</tr>
<tr>
<td>2</td>
<td>Jane Smith</td>
<td>June 21, 2023 2:30 PM</td>
<td>Career Prediction</td>
<td>₹1200.00</td>
<td>Pending</td>
</tr>
</tbody>
</table>
</div>
</div>',
'availability' => '<div class="wrap astrobook-availability">
<h1><?php esc_html_e("Manage Availability", "astrobook"); ?></h1>
<div id="astrobook-availability-calendar"></div>
<button id="astrobook-save-availability" class="button button-primary"><?php esc_html_e("Save Availability", "astrobook"); ?></button>
</div>',
'appointments' => '<div class="wrap astrobook-appointments">
<h1><?php esc_html_e("Appointments", "astrobook"); ?></h1>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th><?php esc_html_e("ID", "astrobook"); ?></th>
<th><?php esc_html_e("Client", "astrobook"); ?></th>
<th><?php esc_html_e("Date", "astrobook"); ?></th>
<th><?php esc_html_e("Time", "astrobook"); ?></th>
<th><?php esc_html_e("Service", "astrobook"); ?></th>
<th><?php esc_html_e("Amount", "astrobook"); ?></th>
<th><?php esc_html_e("Status", "astrobook"); ?></th>
<th><?php esc_html_e("Actions", "astrobook"); ?></th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>John Doe</td>
<td>2023-06-20</td>
<td>10:00 AM - 10:30 AM</td>
<td>Birth Chart Reading</td>
<td>₹1500.00</td>
<td><span class="status-confirmed">Confirmed</span></td>
<td>
<button class="button">Edit</button>
<button class="button button-danger">Cancel</button>
</td>
</tr>
</tbody>
</table>
</div>',
'coupons' => '<div class="wrap astrobook-coupons">
<h1><?php esc_html_e("Coupons", "astrobook"); ?></h1>
<div class="astrobook-coupon-form">
<h2><?php esc_html_e("Add New Coupon", "astrobook"); ?></h2>
<form method="post" action="options.php">
<?php settings_fields("astrobook_settings_group"); ?>
<table class="form-table">
<tr>
<th><label for="coupon_code"><?php esc_html_e("Coupon Code", "astrobook"); ?></label></th>
<td><input type="text" name="coupon_code" id="coupon_code" class="regular-text" required></td>
</tr>
<tr>
<th><label for="discount_type"><?php esc_html_e("Discount Type", "astrobook"); ?></label></th>
<td>
<select name="discount_type" id="discount_type">
<option value="percent"><?php esc_html_e("Percentage", "astrobook"); ?></option>
<option value="fixed"><?php esc_html_e("Fixed Amount", "astrobook"); ?></option>
</select>
</td>
</tr>
<tr>
<th><label for="discount_value"><?php esc_html_e("Discount Value", "astrobook"); ?></label></th>
<td><input type="number" step="0.01" min="0" name="discount_value" id="discount_value" required></td>
</tr>
<tr>
<th><label for="max_uses"><?php esc_html_e("Maximum Uses", "astrobook"); ?></label></th>
<td><input type="number" min="0" name="max_uses" id="max_uses"></td>
</tr>
<tr>
<th><label for="start_date"><?php esc_html_e("Start Date", "astrobook"); ?></label></th>
<td><input type="date" name="start_date" id="start_date"></td>
</tr>
<tr>
<th><label for="end_date"><?php esc_html_e("End Date", "astrobook"); ?></label></th>
<td><input type="date" name="end_date" id="end_date"></td>
</tr>
</table>
<?php submit_button(__("Add Coupon", "astrobook")); ?>
</form>
</div>
<div class="astrobook-coupons-list">
<h2><?php esc_html_e("Existing Coupons", "astrobook"); ?></h2>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th><?php esc_html_e("Code", "astrobook"); ?></th>
<th><?php esc_html_e("Discount", "astrobook"); ?></th>
<th><?php esc_html_e("Uses", "astrobook"); ?></th>
<th><?php esc_html_e("Validity", "astrobook"); ?></th>
<th><?php esc_html_e("Status", "astrobook"); ?></th>
<th><?php esc_html_e("Actions", "astrobook"); ?></th>
</tr>
</thead>
<tbody>
<tr>
<td>WELCOME10</td>
<td>10%</td>
<td>5/20</td>
<td>2023-01-01 to 2023-12-31</td>
<td><span class="status-active">Active</span></td>
<td>
<button class="button">Edit</button>
<button class="button button-danger">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>',
'settings' => '<div class="wrap astrobook-settings">
<h1><?php esc_html_e("AstroBook Settings", "astrobook"); ?></h1>
<form method="post" action="options.php">
<?php settings_fields("astrobook_settings_group"); ?>
<h2><?php esc_html_e("Razorpay Settings", "astrobook"); ?></h2>
<table class="form-table">
<tr>
<th><label for="astrobook_razorpay_key"><?php esc_html_e("Razorpay Key ID", "astrobook"); ?></label></th>
<td><input type="text" name="astrobook_razorpay_key" id="astrobook_razorpay_key" value="<?php echo esc_attr(get_option("astrobook_razorpay_key")); ?>" class="regular-text"></td>
</tr>
<tr>
<th><label for="astrobook_razorpay_secret"><?php esc_html_e("Razorpay Key Secret", "astrobook"); ?></label></th>
<td><input type="password" name="astrobook_razorpay_secret" id="astrobook_razorpay_secret" value="<?php echo esc_attr(get_option("astrobook_razorpay_secret")); ?>" class="regular-text"></td>
</tr>
</table>
<h2><?php esc_html_e("Notification Settings", "astrobook"); ?></h2>
<table class="form-table">
<tr>
<th><label for="astrobook_admin_email"><?php esc_html_e("Admin Notification Email", "astrobook"); ?></label></th>
<td><input type="email" name="astrobook_admin_email" id="astrobook_admin_email" value="<?php echo esc_attr(get_option("astrobook_admin_email", get_option("admin_email"))); ?>" class="regular-text"></td>
</tr>
<tr>
<th><label for="astrobook_client_email_subject"><?php esc_html_e("Client Email Subject", "astrobook"); ?></label></th>
<td><input type="text" name="astrobook_client_email_subject" id="astrobook_client_email_subject" value="<?php echo esc_attr(get_option("astrobook_client_email_subject", "Your Astrology Appointment Confirmation")); ?>" class="regular-text"></td>
</tr>
<tr>
<th><label for="astrobook_client_email_body"><?php esc_html_e("Client Email Body", "astrobook"); ?></label></th>
<td><textarea name="astrobook_client_email_body" id="astrobook_client_email_body" rows="10" class="large-text"><?php echo esc_textarea(get_option("astrobook_client_email_body", "Hello {name},\\n\\nYour appointment is confirmed for {date} at {time}.\\n\\nService: {service}\\nAmount: {price}\\n\\nThank you!")); ?></textarea></td>
</tr>
<tr>
<th><label for="astrobook_admin_email_subject"><?php esc_html_e("Admin Email Subject", "astrobook"); ?></label></th>
<td><input type="text" name="astrobook_admin_email_subject" id="astrobook_admin_email_subject" value="<?php echo esc_attr(get_option("astrobook_admin_email_subject", "New Appointment Booking")); ?>" class="regular-text"></td>
</tr>
<tr>
<th><label for="astrobook_admin_email_body"><?php esc_html_e("Admin Email Body", "astrobook"); ?></label></th>
<td><textarea name="astrobook_admin_email_body" id="astrobook_admin_email_body" rows="10" class="large-text"><?php echo esc_textarea(get_option("astrobook_admin_email_body", "Hello,\\n\\nYou have a new appointment booking:\\n\\nClient: {name}\\nEmail: {email}\\nDate: {date}\\nTime: {time}\\nService: {service}\\nAmount: {price}\\nPayment ID: {payment_id}")); ?></textarea></td>
</tr>
</table>
<h2><?php esc_html_e("General Settings", "astrobook"); ?></h2>
<table class="form-table">
<tr>
<th><label for="astrobook_time_slots"><?php esc_html_e("Time Slot Duration (minutes)", "astrobook"); ?></label></th>
<td>
<select name="astrobook_time_slots[]" multiple class="regular-text" style="height: auto;">
<?php
$slots = get_option("astrobook_time_slots", ["30", "60"]);
$options = [15, 30, 45, 60, 90, 120];
foreach ($options as $option) {
$selected = in_array($option, $slots) ? "selected" : "";
echo '<option value="' . $option . '" ' . $selected . '>' . $option . ' minutes</option>';
}
?>
</select>
<p class="description">Hold Ctrl/Cmd to select multiple options</p>
</td>
</tr>
<tr>
<th><label><?php esc_html_e("Services", "astrobook"); ?></label></th>
<td>
<div id="astrobook-services-container">
<?php
$services = get_option("astrobook_services", array());
if (!empty($services)) {
foreach ($services as $index => $service) {
echo '<div class="astrobook-service">';
echo '<input type="text" name="astrobook_services[' . $index . '][name]" value="' . esc_attr($service["name"]) . '" placeholder="Service Name" class="regular-text">';
echo '<input type="number" name="astrobook_services[' . $index . '][price]" value="' . esc_attr($service["price"]) . '" placeholder="Price" min="0" step="0.01" class="small-text">';
echo '<button type="button" class="button astrobook-remove-service">Remove</button>';
echo '</div>';
}
}
?>
</div>
<button type="button" id="astrobook-add-service" class="button">Add Service</button>
<script>
jQuery(document).ready(function($) {
var serviceIndex = <?php echo count($services) > 0 ? max(array_keys($services)) + 1 : 0; ?>;
$("#astrobook-add-service").click(function() {
var html = \'<div class="astrobook-service">\' +
\'<input type="text" name="astrobook_services[\' + serviceIndex + \'][name]" placeholder="Service Name" class="regular-text">\' +
\'<input type="number" name="astrobook_services[\' + serviceIndex + \'][price]" placeholder="Price" min="0" step="0.01" class="small-text">\' +
\'<button type="button" class="button astrobook-remove-service">Remove</button>\' +
\'</div>\';
$("#astrobook-services-container").append(html);
serviceIndex++;
});
$(document).on("click", ".astrobook-remove-service", function() {
$(this).parent().remove();
});
});
</script>
</td>
</tr>
</table>
<?php submit_button(); ?>
</form>
</div>'
];
foreach ($admin_templates as $name => $content) {
file_put_contents($templates_dir . '/admin/' . $name . '.php', $content);
}
// Create frontend templates
$frontend_templates = [
'calendar' => '<div class="astrobook-frontend-calendar">
<div id="astrobook-calendar"></div>
<div id="astrobook-time-slots" style="display:none; margin-top:20px;">
<h3><?php esc_html_e("Available Time Slots", "astrobook"); ?></h3>
<div id="astrobook-slots-container"></div>
</div>
</div>',
'booking-form' => '<div class="astrobook-booking-form" style="display:none;">
<h3><?php esc_html_e("Book Appointment", "astrobook"); ?></h3>
<p id="astrobook-selected-slot"></p>
<form id="astrobook-appointment-form">
<input type="hidden" id="astrobook-appointment-date">
<input type="hidden" id="astrobook-appointment-start-time">
<input type="hidden" id="astrobook-appointment-end-time">
<div class="form-group">
<label for="astrobook-service"><?php esc_html_e("Service", "astrobook"); ?></label>
<select id="astrobook-service" required>
<option value=""><?php esc_html_e("Select a service", "astrobook"); ?></option>
<?php
$services = get_option("astrobook_services", array());
foreach ($services as $service) {
echo \'<option value="\' . esc_attr($service["name"]) . \'" data-price="\' . esc_attr($service["price"]) . \'>\' . esc_html($service["name"]) . \' - ₹\' . esc_html($service["price"]) . \'</option>\';
}
?>
</select>
</div>
<div class="form-group">
<label for="astrobook-coupon"><?php esc_html_e("Coupon Code (Optional)", "astrobook"); ?></label>
<input type="text" id="astrobook-coupon">
<button type="button" id="astrobook-apply-coupon" class="button"><?php esc_html_e("Apply", "astrobook"); ?></button>
<p id="astrobook-coupon-message"></p>
</div>
<div class="form-group">
<label><?php esc_html_e("Price", "astrobook"); ?></label>
<p id="astrobook-price-display">₹0.00</p>
</div>
<div class="form-group">
<label><?php esc_html_e("Discount", "astrobook"); ?></label>
<p id="astrobook-discount-display">₹0.00</p>
</div>
<div class="form-group">
<label><?php esc_html_e("Total", "astrobook"); ?></label>
<p id="astrobook-total-display">₹0.00</p>
</div>
<button type="submit" class="button button-primary"><?php esc_html_e("Book Now", "astrobook"); ?></button>
</form>
</div>'
];
foreach ($frontend_templates as $name => $content) {
file_put_contents($templates_dir . '/frontend/' . $name . '.php', $content);
}
}
}
// Initialize the plugin
function astrobook_plugin() {
return AstroBook_Plugin::instance();
}
// Start the plugin
astrobook_plugin();