Step 1: Register Custom Post Type
First, we’ll register a custom post type named ‘appointment’ in WordPress.
// Add this code to your plugin file or functions.php
function create_appointment_cpt() {
$labels = array(
'name' => __('Appointments', 'Post Type General Name'),
'singular_name' => __('Appointment', 'Post Type Singular Name'),
'menu_name' => __('Appointments'),
'all_items' => __('All Appointments'),
'add_new_item' => __('Add New Appointment'),
'edit_item' => __('Edit Appointment'),
'new_item' => __('New Appointment'),
'view_item' => __('View Appointment'),
'search_items' => __('Search Appointments'),
'not_found' => __('Not Found'),
'not_found_in_trash' => __('Not Found in Trash')
);
$args = array(
'label' => __('Appointments'),
'labels' => $labels,
'supports' => array('title', 'editor', 'custom-fields', 'author', 'thumbnail', 'excerpt', 'comments', 'revisions'),
'public' => true,
'show_ui' => true,
'show_in_menu' => true,
'show_in_rest' => true,
'menu_position' => 5,
'menu_icon' => 'dashicons-calendar-alt',
'has_archive' => true,
'publicly_queryable' => true,
'exclude_from_search' => false,
'capability_type' => 'post',
'hierarchical' => false,
'rewrite' => array('slug' => 'appointments'),
'query_var' => true,
'taxonomies' => array('category', 'post_tag')
);
register_post_type('appointment', $args);
}
add_action('init', 'create_appointment_cpt');
Step 2: Add Custom Meta Box for Appointment Details
Next, we’ll add a custom meta box to capture appointment details like date, time, name, email, and phone.
// Add this code to your plugin file or functions.php
function appointment_custom_meta_boxes() {
add_meta_box(
'appointment_details',
__('Appointment Details'),
'appointment_details_callback',
'appointment'
);
}
add_action('add_meta_boxes', 'appointment_custom_meta_boxes');
function appointment_details_callback($post) {
wp_nonce_field(basename(__FILE__), 'appointment_nonce');
$appointment_stored_meta = get_post_meta($post->ID);
?>
<!-- Date Input Field -->
<label for="appointment_date"><?php _e('Date', 'your-textdomain'); ?></label>
<input type="date" name="appointment_date" id="appointment_date" value="<?php if (isset($appointment_stored_meta['appointment_date'])) echo $appointment_stored_meta['appointment_date'][0]; ?>" />
<!-- Time Input Field -->
<label for="appointment_time"><?php _e('Time', 'your-textdomain'); ?></label>
<input type="time" name="appointment_time" id="appointment_time" value="<?php if (isset($appointment_stored_meta['appointment_time'])) echo $appointment_stored_meta['appointment_time'][0]; ?>" />
<!-- Name Input Field -->
<label for="appointment_name"><?php _e('Name', 'your-textdomain'); ?></label>
<input type="text" name="appointment_name" id="appointment_name" value="<?php if (isset($appointment_stored_meta['appointment_name'])) echo $appointment_stored_meta['appointment_name'][0]; ?>" />
<!-- Email Input Field -->
<label for="appointment_email"><?php _e('Email', 'your-textdomain'); ?></label>
<input type="email" name="appointment_email" id="appointment_email" value="<?php if (isset($appointment_stored_meta['appointment_email'])) echo $appointment_stored_meta['appointment_email'][0]; ?>" />
<!-- Phone Input Field -->
<label for="appointment_phone"><?php _e('Phone', 'your-textdomain'); ?></label>
<input type="text" name="appointment_phone" id="appointment_phone" value="<?php if (isset($appointment_stored_meta['appointment_phone'])) echo $appointment_stored_meta['appointment_phone'][0]; ?>" />
<?php
}
function save_appointment_meta($post_id) {
if (!isset($_POST['appointment_nonce']) || !wp_verify_nonce($_POST['appointment_nonce'], basename(__FILE__))) {
return;
}
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
if (!current_user_can('edit_post', $post_id)) {
return;
}
if (isset($_POST['appointment_date'])) {
update_post_meta($post_id, 'appointment_date', sanitize_text_field($_POST['appointment_date']));
}
if (isset($_POST['appointment_time'])) {
update_post_meta($post_id, 'appointment_time', sanitize_text_field($_POST['appointment_time']));
}
if (isset($_POST['appointment_name'])) {
update_post_meta($post_id, 'appointment_name', sanitize_text_field($_POST['appointment_name']));
}
if (isset($_POST['appointment_email'])) {
update_post_meta($post_id, 'appointment_email', sanitize_email($_POST['appointment_email']));
}
if (isset($_POST['appointment_phone'])) {
update_post_meta($post_id, 'appointment_phone', sanitize_text_field($_POST['appointment_phone']));
}
}
add_action('save_post', 'save_appointment_meta');
Step 3: Register Custom REST API Endpoints
Now, we’ll register custom REST API endpoints to handle CRUD operations for appointments.
// Add this code to your plugin file or functions.php
function register_appointment_rest_routes() {
register_rest_route('custom/v1', '/appointment/all', array(
'methods' => 'GET',
'callback' => 'get_all_appointments',
'permission_callback' => '__return_true', // Allow access without authentication (for demo)
));
register_rest_route('custom/v1', '/appointment/create', array(
'methods' => 'POST',
'callback' => 'create_appointment',
'permission_callback' => 'is_user_logged_in', // Require logged-in user (for actual usage)
));
register_rest_route('custom/v1', '/appointment/update/(?P<id>\d+)', array(
'methods' => 'POST',
'callback' => 'update_appointment',
'permission_callback' => 'is_user_logged_in', // Require logged-in user (for actual usage)
));
register_rest_route('custom/v1', '/appointment/delete/(?P<id>\d+)', array(
'methods' => 'DELETE',
'callback' => 'delete_appointment',
'permission_callback' => 'is_user_logged_in', // Require logged-in user (for actual usage)
));
register_rest_route('custom/v1', '/appointment/update-status/(?P<id>\d+)', array(
'methods' => 'POST',
'callback' => 'update_appointment_status',
'permission_callback' => 'is_user_logged_in', // Require logged-in user (for actual usage)
));
register_rest_route('custom/v1', '/appointment/user/(?P<user_id>\d+)', array(
'methods' => 'GET',
'callback' => 'get_appointments_by_user',
'permission_callback' => 'is_user_logged_in', // Require logged-in user (for actual usage)
));
}
add_action('rest_api_init', 'register_appointment_rest_routes');
Step 4: Implement Callback Functions for REST API EndpointsFinally, implement the callback functions for each endpoint to perform CRUD operations and retrieve data.
// Define callback functions for REST API endpoints
function get_all_appointments() {
$args = array(
'post_type' => 'appointment',
'posts_per_page' => -1
);
$appointments = get_posts($args);
$data = array();
foreach ($appointments as $appointment) {
$data[] = array(
'id' => $appointment->ID,
'date' => get_post_meta($appointment->ID, 'appointment_date', true),
'time' => get_post_meta($appointment->ID, 'appointment_time', true),
'name' => get_post_meta($appointment->ID, 'appointment_name', true),
'email' => get_post_meta($appointment->ID, 'appointment_email', true),
'phone' => get_post_meta($appointment->ID, 'appointment_phone', true)
);
}
return new WP_REST_Response($data, 200);
}
function create_appointment(WP_REST_Request $request) {
// Sanitize input data
$appointment_date = sanitize_text_field($request['appointment_date']);
$appointment_time = sanitize_text_field($request['appointment_time']);
$appointment_name = sanitize_text_field($request['appointment_name']);
$appointment_email = sanitize_email($request['appointment_email']);
$appointment_phone = sanitize_text_field($request['appointment_phone']);
// Create a new appointment post
$appointment_id = wp_insert_post(array(
'post_type' => 'appointment',
'post_title' => $appointment_phone . ' - ' . $appointment_date,
'post_status' => 'draft' // Set as draft initially
));
// Save meta data
update_post_meta($appointment_id, 'appointment_date', $appointment_date);
update_post_meta($appointment_id, 'appointment_time', $appointment_time);
update_post_meta($appointment_id, 'appointment_name', $appointment_name);
update_post_meta($appointment_id, 'appointment_email', $appointment_email);
update_post_meta($appointment_id, 'appointment_phone', $appointment_phone);
return new WP_REST_Response(array('message' => 'Appointment created successfully'), 200);
}
function update_appointment(WP_REST_Request $request) {
$appointment_id = (int) $request['id'];
// Validate appointment ID
if (!$appointment_id || !get_post($appointment_id)) {
return new WP_Error('invalid_appointment_id', 'Invalid appointment ID', array('status' => 404));
}
// Sanitize input data
$appointment_date = sanitize_text_field($request['appointment_date']);
$appointment_time = sanitize_text_field($request['appointment_time']);
$appointment_name = sanitize_text_field($request['appointment_name']);
$appointment_email = sanitize_email($request['appointment_email']);
$appointment_phone = sanitize_text_field($request['appointment_phone']);
// Update post and meta data
wp_update_post(array(
'ID' => $appointment_id,
'post_title' => $appointment_phone . ' - ' . $appointment_date
));
update_post_meta($appointment_id, 'appointment_date', $appointment_date);
update_post_meta($appointment_id, 'appointment_time', $appointment_time);
update_post_meta($appointment_id, 'appointment_name', $appointment_name);
update_post_meta($appointment_id, 'appointment_email', $appointment_email);
update_post_meta($appointment_id, 'appointment_phone', $appointment_phone);
return new WP_REST_Response(array('message' => 'Appointment updated successfully'), 200);
}
function delete_appointment(WP_REST_Request $request) {
$appointment_id = (int) $request['id'];
// Validate appointment ID
if (!$appointment_id || !get_post($appointment_id)) {
return new WP_Error('invalid_appointment_id', 'Invalid appointment ID', array('status' => 404));
}
// Delete post
wp_delete_post($appointment_id, true);
return new WP_REST_Response(array('message' => 'Appointment deleted successfully'), 200);
}
function update_appointment_status(WP_REST_Request $request) {
$appointment_id = (int) $request['id'];
// Validate appointment ID
if (!$appointment_id || !get_post($appointment_id)) {
return new WP_Error('invalid_appointment_id', 'Invalid appointment ID', array('status' => 404));
}
// Update appointment status (example)
wp_update_post(array(
'ID' => $appointment_id,
'post_status' => 'publish'
));
return new WP_REST_Response(array('message' => 'Appointment status updated successfully'), 200);
}
function get_appointments_by_user(WP_REST_Request $request) {
$user_id = (int) $request['user_id'];
// Query appointments by user ID
$args = array(
'post_type' => 'appointment',
'posts_per_page' => -1,
'author' => $user_id
);
$appointments = get_posts($args);
$data = array();
foreach ($appointments as $appointment) {
$data[] = array(
'id' => $appointment->ID,
'date' => get_post_meta($appointment->ID, 'appointment_date', true),
'time' => get_post_meta($appointment->ID, 'appointment_time', true),
'name' => get_post_meta($appointment->ID, 'appointment_name', true),
'email' => get_post_meta($appointment->ID, 'appointment_email', true),
'phone' => get_post_meta($appointment->ID, 'appointment_phone', true)
);
}
return new WP_REST_Response($data, 200);
}