I'm back to bring you the next part of this series. In this part, we are adding a booking form to the Room’s page which shows all the room’s information. This form allows your customers to submit a booking from frontend easily.

This booking form has some different things from the one we created in part 2, mainly the functionality of fields. Let’s see how.

Before Getting Started

We are going to allow visitors to choose a date without the locked or passed ones in the calendar. So, we need a Datepicker library in addition to the plugins I mentioned in part 1. This is a Javascript library which will help us to do this task.

I chose the Jquery UI Datepicker. There is no need to import this library to your site because Meta Box also uses it for the Date fields. It’s quite convenient. Just read it documentations to learn more about its callbacks and parameters in use.

Now, here we go to finish your booking page.

Show the Booking Form in the Room’s Page for Customer Using

We created a form for internal booking in part 2, so we will get that form once again to show in the room’s page. Then, add some additional configurations and functionalities to the form to meet the customer’s routine.

However, we just show the form in this step. Any further actions will be done later.

Step 1: Get the Shortcode of the Field Group which Show the Booking Form

In the admin dashboard, go to the Meta Box menu > Custom Fields to view all the available field groups. There will be a shortcode beside each one. Choose a shortcode of the field group you need and copy it.

Get the Shortcode of the Field Group which Show the Booking Form

Step 2: Put the Shortcode into the Room’s Page

If you are using a Page Builder plugin, it’s so easy to put the shortcode there.

Suppose that you are using Elementor. Just add a widget for the shortcode type then paste the above shortcode to the content of the widget.

Put the Shortcode into the Room’s Page

Otherwise, if you’re not using any page builder plugin, tackle in your code a little bit as bellow:

  • Create a new file named single-room.php in your theme folder. In there, “room” is the slug of the post type used for the room’s page.
  • Copy all the code in the single.php file then paste to single-room.php.
  • Use the below do_shortcode() function of WordPress and add it to the place where you want to show the booking form.
<?php echo do_shortcode(‘[mb_frontend_form id='booking-fields' post_fields='title,content']’); ?>

In there, [mb_frontend_form id='booking-fields' post_fields='title,content'] is the shortcode of the field group which I copied in step 1.

Put the do_shortcode() into the place you want
Put the do_shortcode() into the place you want

Then, you will see the booking form created in part 2 shown on the room’s page.

the booking form created in part 2

Your website visitor now can fill this form.

Disable the Unnecessary Fields Using CSS

Your customer probably does not care about some information such as order number, booking date, person in charge, etc. So we should disable them in the form.

In the edit page of each field group (Meta Box > Custom Fields), go to the custom field which you want to disable. Eg. the Order Number field. Move to the Appearance tab and add “hide-frontend” to the Custom CSS Class box.

Add a CSS Class for a custom field

Do likewise with the same CSS Class “hide-frontend” for the other fields. After that, go to the file style.css in your theme folder or Customizer screen (Appearance > Customize) and put this CSS code there.

.hide-frontend{
    display: none!important;
}

I want to disable the Add Room button as well, so I also add this CSS code:

.rwmb-button.add-clone {
    display: none!important;
}

Both fields and the Add Room button are disable now.

Settle the Functions of Check-in and Check-out Date Fields

We will use JS for this, so we create a file named custom.js in your theme folder to process JS for the Room’s page only. This will help to speed up the process and avoid unexpected errors.

Paste this code to the functions.php file:

function enqueue_script() {
    if (is_singular('room')) {
        wp_enqueue_script('custom-script', get_template_directory_uri().'/js/custom.js');
    }
}
add_action( 'wp_enqueue_scripts', ‘enqueue_script’);

In there:

  • is_singular(‘room’): to check if the current page is the room’s page which has the post type’s slug is room. This stipulates that the custom.js file is used for the rom’s page only.
  • wp_enqueue_script: to import the custom.js file.
  • get_template_directory_url(): to return the theme’s url

Create a Range for Check-in and Check-out Date

Check-in date always is before the check-out date, so we need to limit their range. When a customer chooses a check-in date, all the dates before it will be locked and can not be chosen.

I use Jquery UI Datepicker here with the following code and add it to the custom.js file.

jQuery( function($) {
    var dateFormat = "yy-mm-dd",
        from = $( "#group_booking_check_in" )
        .datepicker({
        defaultDate: "+1w",
        changeMonth: true,
        })
        .on( "change", function() {
        console.log('helloo');
        to.datepicker( "option", "minDate", getDate( this ) );
        }),
        to = $( "#group_booking_check_out" ).datepicker({
        defaultDate: "+1w",
        changeMonth: true,
        })
        .on( "change", function() {
        from.datepicker( "option", "maxDate", getDate( this ) );
        });

    function getDate( element ) {
        var date;
        try {
        date = $.datepicker.parseDate( dateFormat, element.value );
        } catch( error ) {
        date = null;
        }
        return date;
    }
} );

In there, #group_booking_check_in and #group_booking_check_out are the IDs of the check-in date and check-out date fields in turn. You should replace these IDs with your ones.

Get the field’s ID
Get the field’s ID

You will get this:

Create a Range for Check-in and Check-out Date

Check the Vacancy and Lock Those Days are Out of Room

This is the key of this series. I tried many ways and finally found out the most simple and optimized one.

Step 1: Create an Option to Store the Booking Dates

Whenever a booking is generated, the values of the booking dates will be input to this option with the corresponding room’s ID.

Option’s value is an array as below:

array(
    room_1 => array(
        booking_1 => array(
            key_1 => array(date1, date2),
            key_2 => array(date2, date3),
        )
        booking_2 => array(
            key_1 => array(date1, date2),
            key_2 => array(date2, date3),
        )
    ),
    room_2 => array(
        booking_1 => array(
            key_1 => array(date1, date2),
            key_2 => array(date2, date3),
        )
    )
)

In there:

  • room_1, room_2, … are rooms’ IDs
  • booking_1, booking_2, … are bookings’ IDs
  • key_1, key_2, … are the number order of the cloned group
  • date1, date2, … are the booking dates as the booking order

Next, add this below code to the functions.php to create an option named rwmb_bookings with the initial value is an empty array.

if( !get_option('rwmb_bookings') ){
    add_option('rwmb_bookings', array());
}

You may dive in more ways to create an option in WordPress here.

Step 2: Input Values into Option Whenever a Booking is Generated

Add this code to the functions.php file.

add_action( 'rwmb_booking-fields_after_save_post', 'update_bookings_date' );
function update_bookings_date( $post_id ) {
    $bookings = get_post_meta( $post_id, 'group_booking', true ); // Get the value of the group_booking field then put it into $booking
    if (empty($bookings) && !is_array($bookings)) return;
    $option = get_option('rwmb_bookings');
        foreach ($bookings as $key => $booking) { // Run a loop for $booking because this is a field group
            $room = $booking['room']; // $room is the parameter holds the room’s id
            $begin = new DateTime( $booking['check_in'] ); // $begin is the begin date, means the check-in date as well
            $end = new DateTime( $booking['check_out'] ); // $end is the end date, means the check-out date as well
            $interval = new DateInterval('P1D');
            $daterange = new DatePeriod($begin, $interval ,$end); // The DatePeriod function returns an array containing all the dates from the begin to the end date, excluding the end date
            $dates_booking = array();
            foreach($daterange as $date){
                array_push($dates_booking, $date->format("Y-m-d")); // Push the values to the $dates_booking parameter
            }
            $option[$room][$post_id][$key] = $dates_booking; // Assign the value to the $option parameter
        }
        update_option('rwmb_bookings', $option); // Update the 'rwmb_bookings' option
}

In this code, I used the rwmb_{$field_id}_after_save_post hook of Meta Box to push values to the options parameter. There, my  $field_id  is booking-fields. Whereby, whenever a post, which contains the field group with the ID is booking-fields, is saved (means has a new booking order), this hook will execute these following actions:

  • Get values of the check-in and check-out dates
  • Use DatePeriod functions of PHP to expose all the dates between these dates.
  • Push the above dates (excluding the check-out date) into the option parameter with the corresponding room_id.

Step 3: Check Those Days are Out of Room and the Vacancy from the Option Parameter

Still in the functions.php file, add this code:

function amounts_by_date($room_id){
    $bookings = get_option('rwmb_bookings')[$room_id];
    $dates = array();
    foreach ($bookings as $booking) {
        foreach ($booking as $value) {
            foreach ($value as $k ) {
                array_push($dates, $k);
            }
        }
    }
    return array_count_values($dates);
}

By this, we got the room_id of the room which your customer is viewing, then compare it with the options parameter exporting an array containing dates has booking along with the number of booked rooms of that room type. For example:

Array (
    [2019-12-18] => 1
    [2019-12-19] => 2
    [2019-12-20] => 1
    [2019-12-21] => 1
    [2020-01-31] => 1
    [2020-02-01] => 1
)

As the values in this array, there are 6 days which has a booking for the viewing room type. There are two rooms booked in 2019-12-19 and only one room in the 5 other days. So far, you do not know which day has the vacant room.

In the event that this room type has 2 rooms. So that, you are out of the Family room in 2019-12-19 only which needs to be locked on the calendar.

That’s why you need to check the quantity of rooms of the viewing room type to check the exact date is out of the room by using this:

$quantity = rwmb_meta( 'quantity', $room_id);

Ok, now rename the above function from amounts_by_date($room_id) to be dates_disable() as the following:

function dates_disable($room_id){
    $bookings = get_option('rwmb_bookings')[$room_id];
    if (empty($bookings) && !is_array($bookings)) return;
    $dates = array();
    $disable = array();
    foreach ($bookings as $booking) {
        foreach ($booking as $value) {
            foreach ($value as $k ) {
                array_push($dates, $k);
            }
        }
    }
    $dates = array_count_values($dates);
    $quantity = rwmb_meta( 'quantity', $room_id);
    foreach ($dates as $key => $date) {
        if ($date >= $quantity) {
            array_push($disable, $key);
        }
    }
    return $disable;
}

This function will return only the dates we need to lock. Thus, when you want to use this date, just call the parameter:

$disable = dates_disable($room_id);

Instead of putting them all into a function as I did, you can use a parameter assigned by the first function then create a new function to check.

Step 4: Lock Those Dates in the Check-in and Check-out Date field using Javascript

We will assign a PHP parameter (dates_disable) to a JS’s one to disable the dates by jQuery Datepicker UI.

Paste this following code to the function used to import custom.js, under the wp_enqueue_script()... line.

wp_localize_script( 'custom-script', 'disable_dates', json_encode(dates_disable(get_the_ID())));
Transmit the “dates_disable" parameter to JS
Transmit the “dates_disable" parameter to JS

To check if you did it right, do console.log(disable_dates) then open the console tab on the room’s page. Remember to create some booking first, then you can check it more perfectly.

Next, add this code to the custom.js file to lock the dates are out of room.

from.add(to).datepicker({
    beforeShowDay: function(date){
        var string = jQuery.datepicker.formatDate('yy-mm-dd', date);
        return [ dates_disable.indexOf(string) == -1 ]
    }
});

In there:

  • From, to: are to parameters used in the step of creating the date range.
  • Dates_disable is an array store which days we want to lock

You can see that the date 2019-12-19 is locked now:

Lock Those Dates in the Check-in and Check-out Date field using Javascript

Step 5: Optimize to the Option Parameter

As you can see, this option parameter contains unlimited values of the booking dates. This will weight your database and slow down the checking process.

For this reason, you should optimize it in addition to exclude all the days before the current date. It will reduce the number of values in your option parameter.

We’ll use both two following functions:

function array_filter_recursive ($data) {
    $original = $data;
    $data = array_filter($data);
    $data = array_map(function ($e) {
    return is_array($e) ? array_filter_recursive($e) : $e;
    }, $data);
    return $original === $data ? $data : array_filter_recursive($data);
}
function optimal_bookings_option() {
    $bookings = get_option('rwmb_bookings');
    if (empty($bookings) && !is_array($bookings)) return;
    $today = date("Y-m-d");
    foreach ($bookings as $key_1 => $bk_1) {
        foreach ($bk_1 as $key_2 => $bk_2) {
            foreach ($bk_2 as $key_3 => $bk_3 ) {
                foreach ($bk_3 as $key_4 => $bk_4) {
                    if ($bk_4 > $today) {
                unset($bookings[$key_1][$key_2][$key_3][$key_4]);
                    }
                }

            }
        }
    }
    $bookings = array_filter_recursive($bookings);
    update_option('rwmb_bookings', $bookings);
}

add_action( 'init', 'optimal_bookings_option' );

In there:

  • optimal_bookings_option() helps to compare the booking date with the current date and remove the past date in the Option.
  • array_filter_recursive() helps to filter and remove all the empty arrays and empty values.

I decided to use array_filter_recursive() because right after removing some booking date, I got some empty values as below:

array(2) {

    [451]=> array(2) {
        [0]=> array(2) { }

        [2]=> array(3) {}
    }
    [440]=> array(1) {
        [0]=> array(2) {
            [0]=> string(10) "2020-01-31"
            [1]=> string(10) "2020-02-01"
        }
    }
}

The array_filter_recursive() function helps me to remove the two empty arrays in the array [451]. I found this technique on php.net, you can refer to it.

Add Conditions for Dates in Booking

Although we locked some dates, it is tackled in the display. If your customer is a coder, he absolutely can hack it to choose a locked date.

So, we should add some conditions to your booking date to avoid unexpected errors:

  • The check-in and check-out dates must not coincide with the locked dates.
  • The check-in date must be after the current date.

The valid booking must satisfy both the above conditions.

I use rwmb_frontend_validate to check these above conditions.

add_filter( 'rwmb_frontend_validate', function( $validate, $config ) {
    if ( 'booking-fields' !== $config['id'] ) {
        return $validate;
    }
    $disable_dates = dates_disable(get_the_ID());
        $checkin = date("Y-m-d", strtotime($_POST['group_booking_check_in']));
        $checkout = date("Y-m-d", strtotime($_POST['group_booking_check_out']));

    if ( false !== array_search($checkin, $disable_dates)) {
        $validate = false;
    } else {
        update_post_meta($config['post_id'], 'group_booking_room', get_the_ID());
    }
    return $validate;

}, 10, 2 );

By this, I checked if the booking is valid. If not, we should notify your customer that they have booked unsuccessfully.

Final Words

You have finished all the booking pages and forms for both internal and external use already. We will continue to the next post with the booking management page. This will help the hotel owner have an overall view about the stock. Wait for me in the next part.

In addition, for your quick reference, these are all the source code which I made so far.

  • Full source code of the custom.js file:



This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters


jQuery( function($) {
setTimeout(function(){
datepicker_reinstall();
console.log(disable_dates);
}, 1000);
function datepicker_reinstall(){
var dateFormat = "yy-mm-dd",
from = $( "#group_booking_check_in" ),
to = $( "#group_booking_check_out" );
from.add(to).datepicker('destroy');
from.datepicker({
minDate: 0,
defaultDate: "+1w",
beforeShowDay: function(date){
var string = jQuery.datepicker.formatDate('yy-mm-dd', date);
return [ disable_dates.indexOf(string) == -1 ]
}
})
.on( "change", function() {
to.datepicker( "option", "minDate", getDate( this ) );
});
to.datepicker({
defaultDate: "+1w",
beforeShowDay: function(date){
var string = jQuery.datepicker.formatDate('yy-mm-dd', date);
return [ disable_dates.indexOf(string) == -1 ]
}
})
.on( "change", function() {
from.datepicker( "option", "maxDate", getDate( this ) );
});
function getDate( element ) {
var date;
try {
date = $.datepicker.parseDate( dateFormat, element.value );
} catch( error ) {
date = null;
}
return date;
}
}
} );
view raw

custom.js

hosted with ❤ by GitHub
  • Full source code of the single-room.php file:



This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters


<?php get_header(); ?>
<div id="primary" class="content-area">
<main id="main" class="site-main">
<?php
while ( have_posts() ) : the_post();
get_template_part( 'template-parts/content', 'single' );
the_post_navigation();
echo do_shortcode("[mb_frontend_form id='booking-fields' post_fields='title,content']");
if ( comments_open() || get_comments_number() ) :
comments_template();
endif;
endwhile;
?>
</main>
</div>
<?php get_footer(); ?>
view raw

single-room.php

hosted with ❤ by GitHub
  • Full source code of the functions.php file:



This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters


if ( ! get_option( 'rwmb_bookings' ) ) {
add_option( 'rwmb_bookings', array() );
}
add_action( 'rwmb_booking-fields_after_save_post', 'update_bookings_date' );
function update_bookings_date( $post_id ) {
$bookings = get_post_meta( $post_id, 'group_booking', true );
if ( empty( $bookings ) || ! is_array( $bookings ) ) {
return;
}
$option = get_option( 'rwmb_bookings' );
foreach ( $bookings as $key => $booking ) {
$room = $booking['room'];
$begin = new DateTime( $booking['check_in'] );
$end = new DateTime( $booking['check_out'] );
$interval = new DateInterval('P1D');
$daterange = new DatePeriod($begin, $interval ,$end);
$dates_booking = array();
foreach($daterange as $date){
array_push($dates_booking, $date->format("Y-m-d"));
}
$option[$room][$post_id][$key] = $dates_booking;
}
update_option('rwmb_bookings', $option);
}
function dates_disable($room_id){
$bookings = get_option('rwmb_bookings')[$room_id];
if (empty($bookings) && !is_array($bookings)) return;
$dates = array();
$disable = array();
foreach ($bookings as $booking) {
foreach ($booking as $value) {
foreach ($value as $k ) {
array_push($dates, $k);
}
}
}
$dates = array_count_values($dates);
$quantity = rwmb_meta( 'quantity', $room_id);
foreach ($dates as $key => $date) {
if ($date >= $quantity) {
array_push($disable, $key);
}
}
return $disable;
}
function enqueue_script() {
if (is_singular('room')) {
wp_enqueue_script('custom-script', get_template_directory_uri().'/js/custom.js', array( 'jquery' ));
wp_localize_script( 'custom-script', 'ajaxurl', admin_url('admin-ajax.php'));
wp_localize_script( 'custom-script', 'disable_dates', json_encode(dates_disable(get_the_ID())));
}
}
add_action( 'wp_enqueue_scripts', 'enqueue_script');
/**
* Remove expired date in variable option
*/
function array_filter_recursive ($data) {
$original = $data;
$data = array_filter($data);
$data = array_map(function ($e) {
return is_array($e) ? array_filter_recursive($e) : $e;
}, $data);
return $original === $data ? $data : array_filter_recursive($data);
}
function optimal_bookings_option() {
$bookings = get_option('rwmb_bookings');
$today = date("Y-m-d");
foreach ($bookings as $key_1 => $bk_1) {
foreach ($bk_1 as $key_2 => $bk_2) {
foreach ($bk_2 as $key_3 => $bk_3 ) {
foreach ($bk_3 as $key_4 => $bk_4) {
if ($bk_4 < $today) {
unset($bookings[$key_1][$key_2][$key_3][$key_4]);
}
}
}
}
}
$bookings = array_filter_recursive($bookings);
update_option('rwmb_bookings', $bookings);
}
add_action( 'init', 'optimal_bookings_option' );
add_filter( 'rwmb_frontend_validate', function( $validate, $config ) {
if ( 'booking-fields' !== $config['id'] ) {
return $validate;
}
$disable_dates = dates_disable(get_the_ID());
$checkin = date("Y-m-d", strtotime($_POST['group_booking_check_in']));
$checkout = date("Y-m-d", strtotime($_POST['group_booking_check_out']));
if ( false !== array_search($checkin, $disable_dates)) {
$validate = false;
} else {
update_post_meta($config['post_id'], 'group_booking_room', get_the_ID());
}
return $validate;
}, 10, 2 );
view raw

function.php

hosted with ❤ by GitHub

 

Other case studies you might be interested in

  1. Create A Dynamic Landing Page in WordPress Using Custom Field
  2. Create a Filter to Find Hotels by Location
  3. Create an OTA Website Like Booking.com with Meta Box Plugin - P1: Create a Page to Introduce Hotel Rooms
  4. Create an OTA Website Like Booking.com with Meta Box Plugin - P2: Create Filters on the Archive Page
  5. Create an OTA Website Like Booking.com with Meta Box Plugin - P3: Create Filters for Single Hotel Pages
  6. Create Dynamic Favicon in WordPress using Meta Box plugin
  7. Create Posts Series in WordPress Using Meta Box
  8. Display The Latest Products Section - P2 - Using Meta Box and Elementor
  9. Display The Latest Products Section - P3 - Using Meta Box And Oxygen
  10. How to Add Custom Fields for WooCommerce - P2 - Using MB Views
  11. How to Add Custom Fields to Display Banners using Meta Box Plugin
  12. How to Add Guest Authors and Guest Posts - Using Meta Box
  13. How to Add Related Posts - Using Custom Fields
  14. How to Build a Hotel Booking Website Using Meta Box - P1
  15. How to Build a Hotel Booking Website Using Meta Box - P2 - Booking Page in Backend
  16. How to Build a Hotel Booking Website Using Meta Box - P4 - Booking Management Page
  17. How to Build a Hotel Booking Website Using Meta Box – P3 – Booking Page for Customer
  18. How to Create a Classified Ads Website using Meta Box
  19. How to create a FAQs page - P5 - Using Meta Box and Breakdance
  20. How to Create a Product Page - P2 - Using Meta Box and Oxygen
  21. How to Create a Product Page - P3 - Using Meta Box and Bricks
  22. How to Create a Product Page - P4 - Using Meta Box and Elementor
  23. How to Create a Product Page - P5 - Using Meta Box and Gutenberg
  24. How to Create a Product Page - P6 -Using Meta Box and Breakdance
  25. How to Create a Product Page - P7 - Using Meta Box + Kadence
  26. How to Create a Product Page - P8 - Using Meta Box and Brizy
  27. How to Create a Product Page - P9 - Using Meta Box and Divi
  28. How to Create a Product Page using Meta Box Plugin
  29. How to Create a Recipe - P2 - Using Meta Box and Oxygen
  30. How to Create a Recipe - P3 - Using Meta Box and Elementor
  31. How to Create a Recipe - P4 - Using Meta Box and Bricks
  32. How to Create a Recipe - P5 - Using Meta Box and Zion
  33. How to Create a Recipe - P6 - Using Meta Box and Brizy
  34. How to Create a Recipe - P7 - Using Meta Box and Breakdance
  35. How to Create a Recipe - P8 - Using Meta Box and Kadence
  36. How to Create a Recipe - P9 - Using Meta Box and Divi
  37. How to Create a Recipe with Meta Box Plugin
  38. How to Create a Simple Listing - P2 - Using Meta Box and Bricks
  39. How to Create a Simple Listing - P3 - Using Meta Box and Breakdance
  40. How to Create a Simple Listing - P4 - Using Meta Box and Elementor
  41. How to Create a Team Members Page - P1- Using Meta Box and Elementor
  42. How to Create a Team Members Page - P2 - Using Meta Box and Oxygen
  43. How to Create a Team Members Page - P3 - Using Meta Box and Bricks
  44. How to Create a Team Members Page - P4 - Just Meta Box
  45. How to Create a Team Members Page - P6 - using Meta Box and Breakdance
  46. How to Create a Team Members Page - P7 - Using Meta Box and Kadence
  47. How to Create a Video Gallery Page - P2 - Using Meta Box + Bricks
  48. How to Create a Video Gallery Page - P3 - Using Meta Box and Breakdance
  49. How to Create a Video Gallery Page - P4 - Using Meta Box + Elementor
  50. How to Create a Video Gallery Page - P5 - Using MB Views
  51. How to Create a Video Gallery Page - P6 - Using Meta Box and Zion
  52. How to Create a Video Gallery Page Using Meta Box + Oxygen
  53. How to Create ACF Flexible Content Field with Meta Box
  54. How to Create an Auto-Updated Cheat Sheet in WordPress
  55. How to Create an FAQs Page - P1 - Using Meta Box and Elementor
  56. How to create an FAQs page - P2 - Using Meta Box and Oxygen
  57. How to create an FAQs page - P4 - Using Meta Box and Bricks
  58. How to Create an FAQs Page - P6 - Using MB Views
  59. How to Create an FAQs Page - P7 - Using Meta Box and Divi
  60. How to Create an FAQs Page - P8 - Using Meta Box and Kadence
  61. How to Create an FAQs Page -P3- Using Meta Box
  62. How to Create Buttons with Dynamic Link using Custom Fields
  63. How to Create Category Thumbnails & Featured Images Using Custom Fields
  64. How to Create Download and Preview Buttons - P1 - Using Meta Box and Bricks
  65. How to Create Download and Preview Buttons - P2 - Using Meta Box and Oxygen
  66. How to Create Download and Preview Buttons - P3 - Using MB Views
  67. How to Create Download Buttons in WordPress - Using Custom Fields
  68. How to Create Dynamic Landing Page in WordPress - P1 - Using Meta Box and Elementor
  69. How to Create Dynamic Landing Page in WordPress - P2 - Using Meta Box and Bricks
  70. How to Create Menus for Restaurants - P1 - Using Meta Box and Elementor
  71. How to Create Menus for Restaurants - P2- Using Meta Box and Bricks
  72. How to Create Notification Using Custom HTML Field
  73. How to Create Online Admission Form for School or University
  74. How to Create Online Reservation Form for Restaurants using Meta Box
  75. How to Create Relationships - P1 - Using Meta Box and Oxygen
  76. How to Create Relationships - P2 - Using Meta Box and Bricks
  77. How to Create Relationships - P3 - Using MB Views
  78. How to Create Relationships - P4 - Using Meta Box and Breakdance
  79. How to Create Taxonomy Thumbnails & Featured Images - P2 - Using Meta Box and Oxygen
  80. How to Create Taxonomy Thumbnails & Featured Images - P3 - Using Meta Box and Bricks
  81. How to Create Taxonomy Thumbnails & Featured Images - P4 - Using MB Views
  82. How to Create YouTube Video Timestamps on WordPress Website - P1 - Using MB Views
  83. How To Display All Listings On A Map With Meta Box
  84. How to Display Author Bio in WordPress - P1 - Using Meta Box and Bricks
  85. How to Display Images from Cloneable Fields - P1 - with Gutenberg
  86. How to Display Images from Cloneable Fields - P2 - Using Meta Box and Oxygen
  87. How to Display Images from Cloneable Fields - P3 - with Elementor
  88. How to Display Images from Cloneable Fields - P4 - with Bricks
  89. How to Display Opening Hours for Restaurants - P1 - Using Meta Box + Gutenberg
  90. How to Display Opening Hours for Restaurants - P2 - Using Meta Box and Oxygen
  91. How to Display Product Variations - P1 - Using Meta Box and Gutenberg
  92. How to Display Product Variations - P2 - Using Meta Box and Oxygen
  93. How to Display Product Variations - P3 - Using Meta Box and Bricks
  94. How to Display the Dynamic Banners - P2 - Using Meta Box and Bricks
  95. How to Display The Latest Products - P5 - Using Meta Box and Bricks
  96. How to Display the Latest Products - P6 - using Meta Box and Breakdance
  97. How to Display the Latest Products - P7 - Using Meta Box + Kadence
  98. How to Display the Latest Products Section - P4 - Using Meta Box + Zion
  99. How to Display the Most Viewed Posts - P1 - using MB Views

2 thoughts on “How to Build a Hotel Booking Website Using Meta Box – P3 – Booking Page for Customer

  1. Hi thx for prowiding the hotel booking.
    We would be very happy if we could get an opinion on transportation. especially about the transfer from the airport to the hotels.
    We can't find much reference on this subject.

    1. Thanks for your idea. We will consider creating some articles about transportation.

Leave a Reply

Your email address will not be published. Required fields are marked *