Tạo form đặt bàn cho nhà hàng dùng plugin Meta Box

Thời gian này, việc các nhà hàng cho phép khách hàng đặt bàn ngay từ trên website cũng trở nên khá phổ biến rồi. Vậy nên, hôm nay mình sẽ hướng dẫn các bạn tạo một form đặt bàn cho một nhà hàng nhé. Tất nhiên là khi đặt bàn sẽ không chỉ đơn giản là chỉ đưa thông tin khách hàng, mà ở đây mình sẽ có thêm một vài thứ khác nữa như cho phép khách hàng chọn trước món ăn hay phòng riêng (nếu muốn) và tính tiền để họ biết trước tổng tiền nữa.

Tạo form đặt bàn cho nhà hàng bằng Meta Box

Cùng xem cách làm nhé.

Chuẩn bị

Như đã viết ngay trên tiêu đề, tất nhiên là mình sẽ dùng plugin Meta Box trong bài này rồi. Mình sẽ dùng plugin này để tạo các custom field cho phép nhập thông tin của form đặt bàn. Ngoài ra, mình sẽ cần thêm các extension của chính plugin này để có thêm các tính năng nâng cao nữa, bao gồm:

  • MB Custom Post Types & Custom Taxonomies: cho phép mình tạo custom post type và taxonomy với giao diện trực quan;
  • Meta Box Builder: cung cấp cho mình giao diện trực quan để tạo custom field;
  • MB Frontend Submission: đưa các custom field ra ngoài frontend và cho phép người dùng nhập liệu trực tiếp từ frontend;
  • MB Admin Columns: hiển thị các custom fields như các cột ở giao diện quản lý bài viết, giúp admin xem các thông tin / dữ liệu đã được nhập vào các custom field dễ dàng hơn. Cái này mình chỉ dùng thêm cho tiện việc quản lý của mình thôi, không phải là bắt buộc nên bạn có thể tùy chọn dùng hoặc là không.

Tất cả các extension này đều có sẵn trong Meta Box AIO. Nếu bạn đã sở hữu gói Developer hoặc Lifetime của Meta Box thì bạn chỉ cần kích hoạt chúng ngay trong Meta Box AIO là được nhé. Còn nếu chưa, thì bạn có thể mua riêng lẻ chúng tại website của Meta Box, hoặc mua các gói để tiết kiệm hơn.

Video hướng dẫn

Dưới đây là video hướng dẫn (bằng tiếng Anh), bạn có thể bật sub lên để theo dõi nhé.

Bước 1: Tạo một custom post type mới

Để lưu các thông tin đơn đặt bàn, chúng ta sẽ cần tạo một post type mới. Mỗi bài viết của post type này sẽ là một đơn đặt bàn từ một khách hàng.

Vào menu Meta Box > Post Types > New Post Type và tạo một post type mới tên là Reservation.

Dùng Meta Box tạo một post type mới tên là Reservation.

Bạn có thể xem thêm hướng dẫn cách thiết lập chi tiết cho post type tại video này nhé.

Bước 2: Tạo custom field cho form đặt bàn

Một form đặt bàn thì thường sẽ có các thông tin liên hệ của khách hàng như tên, số điện thoại, email, hay thông tin về số lượng thực khách, số trẻ em, ngày / giờ, loại bàn hoặc loại phòng riêng muốn đặt.

Tuy nhiên, trong hướng dẫn này, mình sẽ làm hơi khác một chút, đó là cho phép khách hàng đặt trước set ăn và tính tiền cho bữa ăn luôn. Nên mình sẽ có thêm 2 trường thông tin là chọn set ăn và tổng tiền nữa.

Tạo custom field cho form đặt bàn

Về thiết lập của các field, có một số điểm đặc biệt mình cần lưu ý ở đây như sau:

Trường Tên

Trường thông tin Tên (tên của người đặt bàn) mình sẽ đặt luôn ID là post_title để tên người đặt sẽ được lưu luôn thành tên của bài viết.

Các trường Chọn set ăn và Chọn phòng riêng

Trường thông tin Chọn set ăn mình chọn loại field là Select, và ở phần Choices, mình đưa vào các option như sau:

Cài đặt thông tin cho trường Chọn set ăn

Trong đó: các con số bên trái dấu hai chấm (:) là giá của các set đồ ăn (đơn vị tính là VND), và bên phải là tên ví dụ cho các set đồ ăn của mình.

Tương tự với trường Chọn phòng riêng, mình cũng đặt giá của mỗi loại phòng tương ứng với tên loại phòng như sau:

Cài đặt thông tin cho trường Chọn phòng riêng

Hiển thị các field dạng admin column

Để tiện quản lý thông tin các đơn đặt bàn, mình muốn hiển thị luôn thông tin các field ngay ở giao diện quản lý bài viết. Vì vậy, mình sẽ thiết lập để các field hiển thị dưới dạng admin column. Để làm được việc này thì bạn cần kích hoạt extension MB Admin Columns nhé.

Ở phần thiết lập cho từng field, bạn hãy tick vào mục Show as an admin column nhé. Sau đó, bạn sẽ thấy một số thiết lập khác xuất hiện để bạn thiết lập thêm cho admin column này.

Tạo thiết lập cho từng field

Lưu ý là bạn cần phải chọn một vị trí cho phần Column position.

Cuối cùng, đừng quên chọn Location ở phần Settings là loại post type mà mình vừa tạo.

Chọn post type là Location ở phần Settings

Và bạn sẽ thấy, ở phần quản lý các bài viết trong phần Reservations của mình lúc này đã xuất hiện các cột nội dung như sau:

Các cột hiển thị ở phần quản lý các bài viết trong phần Reservations

Bước 3: Tạo trang đặt bàn

Tạo template cho trang đặt bàn

Trang đặt bàn của mình sẽ có một giao diện hơi khác các trang khác trên website, nên mình sẽ tạo một template mới cho nó. Trong folder templates của theme, mình tạo thêm một file .php với nội dung như sau:

<?php
/**
 * Template Name: Reservation Page
 */
get_header();
if( have_posts() ) :
    while ( have_posts() ) :
        the_post();
        ?>
        <main id="main" class="site-main" role="main">
            <div class="col-left">
                <?php the_content(); ?>
                <div id="total1"></div>
            </div>
            <div class="col-right">
                <?php dynamic_sidebar( 'sidebar-1' );?>
            </div>
        </main>
        <?php
        endwhile;
endif;
get_footer();

Trong đó, sidebar-1 là ID của Sidebar mà mình đã tạo sẵn như sau:

Sử dụng iframe để thêm Google Maps vào trang đặt chỗ

Trong sidebar này, mình có nhúng sẵn một iframe của Google Maps để pin địa chỉ của nhà hàng trên bản đồ, và đặt thêm các thông tin liên hệ của nhà hàng.

Sau khi chọn trang đặt bàn có template là Reservation Page (tên của template mà mình vừa tạo) thì trang có giao diện như sau:

Trang đặt chỗ với bản đồ và thông tin liên hệ của nhà hàng

Thêm form đặt bàn lên trang

Khi đã kích hoạt extension MB Frontend Submission, bạn sẽ thấy Meta Box tự tạo shortcode sẵn cho các field group ở đây.

Extension MB Frontend Submission, của Meta Box tạo shortcode sẵn cho các field group

Đoạn shortcode thường sẽ có dạng:

[mb_frontend_form id='reservation' post_fields='title,content']

Tuy nhiên, mình không muốn hiển thị field Title và Content nên mình sẽ xóa attribute post_fields đi nhé.

Và, mình dán đoạn code này vào nội dung trang đặt bàn như sau.

Dán đoạn shortcode để hiển thị form đặt bàn

Trong đó, mình có thêm một attribute để thêm button nhé. Và đây là kết quả.

Form đặt bàn hiển thị ngoài frontend

Style cho các thành phần trên trang hiển thị đẹp hơn

Các field hiển thị vẫn chưa được bắt mắt lắm, nên mình sẽ dùng CSS để style lại một chút như sau:

#reservation {
  width: 100%; }

.page-template-reservation-page .site-main {
  width: 100%;
  display: grid; }

.no-sidebar .main {
  margin: 0; }

.rwmb-label, .rwmb-input {
  width: 100% !important;
  padding-bottom: 10px; }

.rwmb-input input {
  width: 100%; }

.rwmb-input select {
  width: 100%; }

.page-template-reservation-page .site-main {
  width: 100%;
  display: grid; }

@media all and (min-width: 768px) {
  .page-template-reservation-page .site-main {
    grid-template-columns: 1fr 30%;
    grid-gap: 30px; } }

.eci-info {
  font-size: 16px; }
  .eci-info svg {
    width: 20px !important;
    min-width: 20px !important;
    max-width: 20px !important;
    height: 20px !important; }

.rwmb-input-group-text {
  border: 0 !important; }

.rwmb-button {
  padding: 10px 25px;
  background: #ea0808;
  text-transform: uppercase; }

.calendar .rwmb-input, .adults .rwmb-input, .children .rwmb-input, .full-name .rwmb-input, .email .rwmb-input, .phone .rwmb-input, .book .rwmb-input, .black-tie .rwmb-input {
  position: relative;
  padding-bottom: 0; }
  .calendar .rwmb-input input, .calendar .rwmb-input select, .adults .rwmb-input input, .adults .rwmb-input select, .children .rwmb-input input, .children .rwmb-input select, .full-name .rwmb-input input, .full-name .rwmb-input select, .email .rwmb-input input, .email .rwmb-input select, .phone .rwmb-input input, .phone .rwmb-input select, .book .rwmb-input input, .book .rwmb-input select, .black-tie .rwmb-input input, .black-tie .rwmb-input select {
    padding-left: 40px; }
  .calendar .rwmb-input::before, .adults .rwmb-input::before, .children .rwmb-input::before, .full-name .rwmb-input::before, .email .rwmb-input::before, .phone .rwmb-input::before, .book .rwmb-input::before, .black-tie .rwmb-input::before {
    font-family: FontAwesome;
    font-style: normal;
    font-weight: normal;
    text-decoration: inherit;
    color: #000;
    font-size: 18px;
    padding-right: 0.5em;
    position: absolute;
    top: 0px;
    bottom: 0;
    left: 0;
    background: #f0f0f0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 8px; }

.calendar .rwmb-input::before {
  content: "\f073"; }

.adults .rwmb-input::before, .children .rwmb-input::before, .full-name .rwmb-input::before {
  content: "\f007"; }

.email .rwmb-input::before {
  content: "\f003"; }

.phone .rwmb-input::before {
  content: "\f095"; }

.book .rwmb-input::before {
  content: "\f02d"; }

.black-tie .rwmb-input::before {
  content: "\f27e"; }

.col-left, .col-right {
  background: #efefef; }

.col-left {
  padding: 10px; }

.col-right .eci {
  padding: 10px;
  margin-top: 0;
}

Trong đó, reservation-page là tên file của template mà mình đã tạo cho trang đặt bàn này, và các class như calendar, adults, book, …

Ở đây, mình dùng FontAwesome và thêm CSS vào file style.css, nên mình sẽ phải equeue cả 2 cái này ở trong file functions.php như sau:

function child_theme_scripts() {
    wp_enqueue_style('font-awesome', 'https://cdn.jsdelivr.net/fontawesome/4.7.0/css/font-awesome.min.css', '', '4.7.0');
    wp_enqueue_style('estar-child-style', get_stylesheet_directory_uri() . '/style.css', false, '1.0', 'all');
}
add_action( 'wp_enqueue_scripts', 'child_theme_scripts' );

Và form của mình sẽ như thế này:

Trang đặt hàng sau khi được style bằng CSS

Bước 4: Thêm tính năng tính tiền cho form đặt bàn

Lúc này, field tổng tiền vẫn là 0 và dù bạn nhập các thông tin ở trên đầy đủ thì nó vẫn không thay đổi. Để field này có thể tự động tính được tổng số tiền dựa trên số thực khách bao gồm cả người lớn và trẻ em, loại phòng, và set đồ ăn đặt trước, thì mình cần dùng đến code.

Tạo công thức tính tiền

Trong file functions.php của theme, mình thêm đoạn code sau:

add_action( 'wp_ajax_total', 'text_domain_load_total_ajax' );
add_action( 'wp_ajax_nopriv_total', 'text_domain_load_total_ajax' );
function text_domain_load_total_ajax() {
    $adults = $_POST['adults'] ?? 1;
    $children = $_POST['children'] ?? 0;
    $set_lunch = $_POST['set_lunch'] ?? 0;
    $private_room = $_POST['private_room'] ?? 0;
    $total = ( $adults * $set_lunch ) + ( $children * $set_lunch /2 ) + $private_room;
    $total = number_format($total, 0, ',', '.') . 'VND';
    wp_send_json_success( $total );
    die();
}

Trong đó:

  • add_action(): là hook để tạo action tên là 'total'.
  • text_domain_load_total_ajax(): là hàm dùng để load toàn bộ giá trị của các biến cần thiết và đưa vào công thức.
  • $adults, $children, $set_lunch, $private_room: là các biến được sử dụng để đưa vào công thức tính tổng tiền.
  • $adults = $_POST['adults'] ?? 1: kiểm tra xem biến adults này đã có giá trị hay chưa, nếu có rồi thì sẽ ghi nhận và sử dụng giá trị đó, nếu chưa thì sẽ áp cho biến giá trị mặc định là 1. Giá trị mặc định này có thể tự đặt, giống như ở các biến khác mình đặt ở đây.
  • number_format (): quy định định dạng cho giá trị dạng số của biến $total với phân cách phần nghìn bằng dấu . và phân cách phần thập phân bằng dấu ,; đồng thời không hiển thị chữ số nào đằng sau dấu phẩy.
  • wp_send_json_success( $total ): trả về kết quả là giá trị của biến total dưới dạng json.

Truyền dữ liệu vào các biến

Mặc dù công thức của mình đã có, nhưng tất cả các biến trong công thức của mình chưa có dữ liệu truyền vào nên các biến này hiện vẫn đang có giá trị mặc định là 0 hoặc 1 như mình đang thiết lập ở trong đoạn code trên.

Vì vậy, mình cần tạo một file script.js vào folder js của theme với nội dung như dưới đây để ghi nhận các giá trị cho các biến mỗi khi người dùng lựa chọn hay thay đổi lựa chọn trên các field của form đặt bàn.

(function($){
    $(document).ready(function(){
        $("#adults, #children, #set_lunch, #private_room").on( 'change', function(){
            var adults = $('#adults').val();
            var children = $('#children').val();
            var set_lunch = $('#set_lunch').val();
            var private_room = $('#private_room').val();
            console.log( set_lunch );
            $.ajax( {
                type: "post",
                dataType: "json",
                url : ReservationParams.ajaxURL,
                data: {
                    action: 'total',
                    adults: adults,
                    children: children,
                    set_lunch: set_lunch,
                    private_room: private_room
                },
                success: function(response) {
                    //console.log(response);
                    $('#amount').val(response.data);
                },
                error: function( jqXHR, textStatus, errorThrown ){
                    console.log( 'The following error occured: ' + textStatus, errorThrown );
                }
            } )
        } )
    })
})(jQuery)

Ở đây, mình đã dùng ajax để load giá trị của các biến. Trong đó:

  • #adults, #children, #set_lunch, #private_room: là ID của các custom field mà mình đã tạo cho form đặt bàn này;
  • adults, children, set_lunch, private_room: chính là các biến ở phần công thức tính tiền phía trên, và trong đoạn code này, mình gán cho chúng giá trị của các trường có ID tương ứng;
  • action: 'total': thông qua ajax, mình gửi giá trị của các biến tới action total đã tạo ở trên với đường dẫn chứa hàm xử lý dữ liệu là url : ReservationParams.ajaxURL;
  • success: function(response): sau khi gửi dữ liệu thành công, thì giá trị trả về là giá trị của biến total ở trên sẽ được in ra custom field có ID là amount.

Enqueue file JS và URL cho ajax

Đến đây thì công thức của chúng ta vẫn chưa chạy được đâu, vì cả file script.jsurl của ajax vừa tạo vẫn chưa được khai báo. Vì vậy, mình cần vào functions.php và thêm đoạn code sau vào ngay trong đoạn function child_theme_scripts() nhé:

wp_enqueue_script( 'theme-script', get_stylesheet_directory_uri() . '/js/script.js', array( 'jquery' ), '1.0', true );
wp_localize_script( 'theme-script', 'ReservationParams', array( 'ajaxURL' => admin_url( 'admin-ajax.php' ) ) );

Lưu ý:

  • 'theme-script': tên này là tự đặt, nhưng bạn chú ý là phải đặt nó ở cả 2 dòng code này giống hệt nhau;
  • 'ReservationParams''ajaxURL' là lấy từ url : ReservationParams'.ajaxURL, bạn có thể thay đổi chúng, nhưng phải thống nhất ở cả hai nơi nhé.

Cuối cùng cũng xong rồi đó. Bây giờ chúng ta có thể test thử xem khi đặt bàn và thay đổi thông tin thì sẽ thế nào nhé.

Test thử xem khi đặt bàn và thay đổi thông tin

Trong phần quản lý bài viết (quản lý danh sách các đơn đặt bàn), mình cũng thấy luôn thông tin đặt bàn mình vừa mới nhập vào. Vậy là ổn rồi đó.

Thông tin đặt bàn được nhập sẽ hiển thị trong phần quản lý bài viết

Lời cuối

Trên thực tế là mình mới chỉ gặp một số trường hợp có yêu cầu đặt set ăn hay phòng ăn riêng và yêu cầu thanh toán trước hoặc là cho biết trước tổng tiền như thế này thôi. Vì vậy, mình cũng không chắc là case study này là phổ biến đâu. Nhưng dù sao thì đây cũng là một trường hợp để mình tham khảo cách làm cho việc tính tiền cho các form đặt hàng. Nên chắc bạn sẽ cần phải biến tấu thêm chút chút cho phù hợp với thực tế áp dụng nữa. Chúc các bạn thành công nha!

Để lại bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *