Plugin Directory

Changeset 3492420


Ignore:
Timestamp:
03/27/2026 08:09:49 AM (7 days ago)
Author:
wpdevelop
Message:

Update 10.15.4

Location:
booking/trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • booking/trunk/includes/_functions/booking_data__parse.php

    r3488732 r3492420  
    574574}
    575575
    576 /**
    577  * Get booking form pair (fields + show template) for listing/inspection purposes,
    578  * but allow BFB resolver to override legacy options.
     576// FixIn: 10.15.4.1.
     577/**
     578 * Extract "advanced_form" from BFB loader result.
     579 *
     580 * @param mixed $bfb_pair
     581 *
     582 * @return string
     583 */
     584function wpbc_extract__advanced_form_from_bfb_pair__for_field_names_listing( $bfb_pair ) {
     585
     586    $containers = array();
     587
     588    if ( ! is_array( $bfb_pair ) ) {
     589        return '';
     590    }
     591
     592    /**
     593     * Safety:
     594     * Do not override if loader already fell back to legacy.
     595     */
     596    if ( isset( $bfb_pair['source'] ) && ( 'builder' !== $bfb_pair['source'] ) ) {
     597        return '';
     598    }
     599
     600    $containers[] = $bfb_pair;
     601
     602    if ( isset( $bfb_pair['pair'] ) && is_array( $bfb_pair['pair'] ) ) {
     603        $containers[] = $bfb_pair['pair'];
     604    }
     605
     606    if ( isset( $bfb_pair['form'] ) && is_array( $bfb_pair['form'] ) ) {
     607        $containers[] = $bfb_pair['form'];
     608    }
     609
     610    foreach ( $containers as $container ) {
     611
     612        if ( isset( $container['form'] ) && is_string( $container['form'] ) ) {
     613            return (string) $container['form'];
     614        }
     615
     616        if ( isset( $container['advanced_form'] ) && is_string( $container['advanced_form'] ) ) {
     617            return (string) $container['advanced_form'];
     618        }
     619    }
     620
     621    return '';
     622}
     623
     624
     625/**
     626 * Extract "content_form" from BFB loader result.
     627 *
     628 * @param mixed $bfb_pair
     629 *
     630 * @return string
     631 */
     632function wpbc_extract__content_form_from_bfb_pair__for_field_names_listing( $bfb_pair ) {
     633
     634    $containers = array();
     635
     636    if ( ! is_array( $bfb_pair ) ) {
     637        return '';
     638    }
     639
     640    /**
     641     * Safety:
     642     * Do not override if loader already fell back to legacy.
     643     */
     644    if ( isset( $bfb_pair['source'] ) && ( 'builder' !== $bfb_pair['source'] ) ) {
     645        return '';
     646    }
     647
     648    $containers[] = $bfb_pair;
     649
     650    if ( isset( $bfb_pair['pair'] ) && is_array( $bfb_pair['pair'] ) ) {
     651        $containers[] = $bfb_pair['pair'];
     652    }
     653
     654    if ( isset( $bfb_pair['form'] ) && is_array( $bfb_pair['form'] ) ) {
     655        $containers[] = $bfb_pair['form'];
     656    }
     657
     658    foreach ( $containers as $container ) {
     659
     660        if ( isset( $container['content'] ) && is_string( $container['content'] ) ) {
     661            return (string) $container['content'];
     662        }
     663
     664        if ( isset( $container['content_form'] ) && is_string( $container['content_form'] ) ) {
     665            return (string) $container['content_form'];
     666        }
     667    }
     668
     669    return '';
     670}
     671
     672
     673/**
     674 * Maybe get booking form pair from BFB using the same resolver chain as front-end rendering.
    579675 *
    580676 * @param int    $resource_id
     
    582678 * @param array  $ctx
    583679 *
    584  * @return array { form:string, content:string }
     680 * @return array
     681 */
     682function wpbc_get__bfb_booking_form_pair__for_field_names_listing( $resource_id = 1, $form_name = 'standard', $ctx = array() ) {
     683
     684    $resource_id = absint( $resource_id );
     685    $form_name   = sanitize_text_field( (string) $form_name );
     686    $ctx         = ( is_array( $ctx ) ) ? $ctx : array();
     687
     688    if ( '' === $form_name ) {
     689        $form_name = 'standard';
     690    }
     691
     692    $owner_user_id = isset( $ctx['owner_user_id'] ) ? absint( $ctx['owner_user_id'] ) : null;
     693
     694    if ( ! class_exists( 'WPBC_FE_Form_Source_Resolver' ) ) {
     695        return array();
     696    }
     697
     698    if ( ! function_exists( 'wpbc_bfb_get_booking_form_pair' ) ) {
     699        return array();
     700    }
     701
     702    $form_status = isset( $ctx['form_status'] ) ? sanitize_key( $ctx['form_status'] ) : 'published';
     703
     704    if ( in_array( $form_status, array( 'publish', 'published' ), true ) ) {
     705        $form_status = 'published';
     706    }
     707    if ( 'preview' !== $form_status ) {
     708        $form_status = 'published';
     709    }
     710
     711    /**
     712     * Preview payload shortcut.
     713     */
     714    if (
     715        ( 'preview' === $form_status )
     716        && function_exists( 'wpbc_bfb_preview__maybe_get_payload_from_context' )
     717    ) {
     718        $payload = wpbc_bfb_preview__maybe_get_payload_from_context( $ctx );
     719
     720        if ( ! empty( $payload ) && is_array( $payload ) ) {
     721
     722            $pair = array(
     723                'form'    => isset( $payload['advanced_form'] ) ? (string) $payload['advanced_form'] : '',
     724                'content' => isset( $payload['content_form'] ) ? (string) $payload['content_form'] : '',
     725            );
     726
     727            if ( ( '' !== trim( $pair['form'] ) ) || ( '' !== trim( $pair['content'] ) ) ) {
     728                return $pair;
     729            }
     730        }
     731    }
     732
     733    $req = array(
     734        'resource_id'     => $resource_id,
     735        'form_slug'       => $form_name,
     736        'form_status'     => $form_status,
     737        'custom_params'   => array(),
     738        'legacy_instance' => null,
     739        'ctx'             => $ctx,
     740    );
     741
     742    if ( null !== $owner_user_id ) {
     743        $req['owner_user_id'] = $owner_user_id;
     744    }
     745
     746    $resolved = WPBC_FE_Form_Source_Resolver::resolve( $req );
     747
     748    // Same behavior as your content resolver: preview can fallback to published.
     749    if (
     750        ( empty( $resolved['engine'] ) || ( 'bfb_db' !== $resolved['engine'] ) )
     751        && ( 'preview' === $form_status )
     752    ) {
     753        $req['form_status'] = 'published';
     754        $resolved           = WPBC_FE_Form_Source_Resolver::resolve( $req );
     755    }
     756
     757    if ( empty( $resolved['engine'] ) || ( 'bfb_db' !== $resolved['engine'] ) ) {
     758        return array();
     759    }
     760
     761    $bfb_loader_args = array();
     762
     763    if ( ! empty( $resolved['bfb_loader_args'] ) && is_array( $resolved['bfb_loader_args'] ) ) {
     764        $bfb_loader_args = $resolved['bfb_loader_args'];
     765    }
     766
     767    $bfb_pair = wpbc_bfb_get_booking_form_pair( $bfb_loader_args );
     768
     769    $pair = array(
     770        'form'    => wpbc_extract__advanced_form_from_bfb_pair__for_field_names_listing( $bfb_pair ),
     771        'content' => wpbc_extract__content_form_from_bfb_pair__for_field_names_listing( $bfb_pair ),
     772    );
     773
     774    if ( '' === trim( $pair['form'] ) && '' === trim( $pair['content'] ) ) {
     775        return array();
     776    }
     777
     778    return $pair;
     779}
     780
     781
     782/**
     783 * Get booking form pair (fields + show template) for listing/inspection purposes.
     784 *
     785 * - Legacy mode: returns legacy form + content.
     786 * - BFB mode: uses resolver and returns advanced_form + content_form.
     787 *
     788 * @param int    $resource_id
     789 * @param string $form_name
     790 * @param array  $ctx
     791 *
     792 * @return array
    585793 */
    586794function wpbc_get__booking_form_pair__for_field_names_listing( $resource_id = 1, $form_name = 'standard', $ctx = array() ) {
    587795
     796    $resource_id = absint( $resource_id );
     797    $form_name   = sanitize_text_field( (string) $form_name );
     798    $ctx         = ( is_array( $ctx ) ) ? $ctx : array();
     799
     800    if ( '' === $form_name ) {
     801        $form_name = 'standard';
     802    }
     803
     804    /**
     805     * ---------------------------------------------------------------------
     806     * Legacy baseline pair.
     807     * ---------------------------------------------------------------------
     808     */
    588809    $pair = array(
    589         'form'    => wpbc_bf__replace_custom_html_shortcodes( get_bk_option( 'booking_form' ) ),
    590         'content' => wpbc_bf__replace_custom_html_shortcodes( get_bk_option( 'booking_form_show' ) ),
     810        'form'    => '',
     811        'content' => '',
    591812    );
    592813
    593     // Let BFB override both "form" and "content" if available.
    594     if ( class_exists( 'WPBC_BFB_Booking_Data_Content_Resolver' ) ) {
    595 
    596         // Recommended: add this method to the resolver (see section 3 below).
    597         if ( method_exists( 'WPBC_BFB_Booking_Data_Content_Resolver', 'maybe_override_booking_form_pair_by_bfb' ) ) {
    598             $pair = WPBC_BFB_Booking_Data_Content_Resolver::maybe_override_booking_form_pair_by_bfb(
    599                 $pair,
    600                 (int) $resource_id,
    601                 (string) $form_name,
    602                 '',       // no form_data here
    603                 (is_array( $ctx ) ? $ctx : array())
     814    // Legacy "fields" configuration.
     815    $pair['form'] = wpbc_get__booking_form_fields__configuration( $resource_id, $form_name );
     816    $pair['form'] = wpbc_bf__replace_custom_html_shortcodes( $pair['form'] );
     817
     818    // Legacy "show/content" configuration.
     819    if ( ! class_exists( 'wpdev_bk_personal' ) ) {
     820
     821        $pair['content'] = wpbc_simple_form__get_form_show__as_shortcodes();
     822        $pair['content'] = wpbc_bf__replace_custom_html_shortcodes( $pair['content'] );
     823
     824    } else {
     825
     826        $pair['content'] = get_bk_option( 'booking_form_show' );
     827        $pair['content'] = wpbc_bf__replace_custom_html_shortcodes( $pair['content'] );
     828
     829        if ( class_exists( 'wpdev_bk_biz_m' ) ) {
     830
     831            $my_booking_form_name = $form_name;
     832
     833            if ( empty( $my_booking_form_name ) ) {
     834                $my_booking_form_name = apply_bk_filter( 'wpbc_get_default_custom_form', 'standard', $resource_id );
     835            }
     836
     837            if ( ( 'standard' !== $my_booking_form_name ) && ( '' !== $my_booking_form_name ) ) {
     838                $pair['content'] = apply_bk_filter( 'wpdev_get_booking_form_content', $pair['content'], $my_booking_form_name );
     839            }
     840
     841            $pair['content'] = apply_bk_filter(
     842                'wpbc_multiuser_get_booking_form_show_of_regular_user',
     843                $pair['content'],
     844                $resource_id,
     845                $my_booking_form_name
    604846            );
     847        }
     848    }
     849
     850    /**
     851     * ---------------------------------------------------------------------
     852     * BFB override.
     853     * ---------------------------------------------------------------------
     854     */
     855    $bfb_pair = wpbc_get__bfb_booking_form_pair__for_field_names_listing( $resource_id, $form_name, $ctx );
     856
     857    if ( ! empty( $bfb_pair ) ) {
     858
     859        if ( isset( $bfb_pair['form'] ) && ( '' !== trim( (string) $bfb_pair['form'] ) ) ) {
     860            $pair['form'] = (string) $bfb_pair['form'];
     861        }
     862
     863        if ( isset( $bfb_pair['content'] ) && ( '' !== trim( (string) $bfb_pair['content'] ) ) ) {
     864            $pair['content'] = (string) $bfb_pair['content'];
     865        }
     866    }
     867
     868    $pair['form']    = wpbc_bf__replace_custom_html_shortcodes( (string) $pair['form'] );
     869    $pair['content'] = wpbc_bf__replace_custom_html_shortcodes( (string) $pair['content'] );
     870
     871    $pair['form']    = wpbc_lang( (string) $pair['form'] );
     872    $pair['content'] = wpbc_lang( (string) $pair['content'] );
     873
     874
     875    return $pair;
     876}
     877
     878/**
     879 * Get arr of all fields names from all booking forms (including custom).
     880 *
     881 * Legacy mode:
     882 * - Keep previous behavior exactly as before.
     883 *
     884 * BFB mode:
     885 * - Load form names via helper.
     886 * - Load each pair through BFB-aware resolver logic.
     887 *
     888 * @return array
     889 */
     890function wpbc_get__in_all_forms__field_names_arr() {
     891
     892    $booking_form_fields_arr = array();
     893
     894    $is_bfb_enabled = (
     895        class_exists( 'WPBC_Frontend_Settings' )
     896        && method_exists( 'WPBC_Frontend_Settings', 'is_bfb_enabled' )
     897        && WPBC_Frontend_Settings::is_bfb_enabled( null )
     898    );
     899
     900    // ---------------------------------------------------------------------
     901    // Legacy mode: keep previous behavior exactly.
     902    // ---------------------------------------------------------------------
     903    if ( ! $is_bfb_enabled ) {
     904
     905        $booking_form_fields_arr[] = array(
     906            'name'    => 'standard',
     907            'form'    => wpbc_bf__replace_custom_html_shortcodes( get_bk_option( 'booking_form' ) ),
     908            'content' => wpbc_bf__replace_custom_html_shortcodes( get_bk_option( 'booking_form_show' ) ),
     909        );
     910
     911        $is_can = apply_bk_filter( 'multiuser_is_user_can_be_here', true, 'only_super_admin' );
     912
     913        if ( ( $is_can ) || ( get_bk_option( 'booking_is_custom_forms_for_regular_users' ) === 'On' ) ) {
     914
     915            $booking_forms_extended = get_bk_option( 'booking_forms_extended' );
     916            $booking_forms_extended = maybe_unserialize( $booking_forms_extended );
     917
     918            if ( is_array( $booking_forms_extended ) ) {
     919                foreach ( $booking_forms_extended as $form_extended ) {
     920                    if ( is_array( $form_extended ) ) {
     921                        $booking_form_fields_arr[] = $form_extended;
     922                    }
     923                }
     924            }
     925        }
     926
     927    // ---------------------------------------------------------------------
     928    // BFB mode: use new resolver-aware logic.
     929    // ---------------------------------------------------------------------
     930    } else {
     931
     932        $ctx = wpbc_get_request_form_context();
     933        $ctx['form_status'] = 'published';
     934
     935        $form_names = array( 'standard' );
     936
     937        if (
     938            class_exists( 'WPBC_FE_Custom_Form_Helper' )
     939            && method_exists( 'WPBC_FE_Custom_Form_Helper', 'get_custom_booking_forms_list' )
     940        ) {
     941            $owner_user_id = 0;
     942
     943            if ( method_exists( 'WPBC_FE_Custom_Form_Helper', 'wpbc_mu__get_current__owner_user_id' ) ) {
     944                $owner_user_id = absint( WPBC_FE_Custom_Form_Helper::wpbc_mu__get_current__owner_user_id() );
     945            }
     946
     947            $ctx['owner_user_id'] = $owner_user_id;
     948
     949            $forms_list = WPBC_FE_Custom_Form_Helper::get_custom_booking_forms_list(
     950                array(
     951                    'include_standard' => false,
     952                    'owner_user_id'    => $owner_user_id,
     953                    'statuses'         => array( 'published' ),
     954                    'list_mode'        => 'auto',
     955                )
     956            );
     957
     958            if ( is_array( $forms_list ) ) {
     959                foreach ( $forms_list as $form_data ) {
     960
     961                    if ( empty( $form_data['name'] ) ) {
     962                        continue;
     963                    }
     964
     965                    $form_name = sanitize_text_field( (string) $form_data['name'] );
     966
     967                    if ( ( '' !== $form_name ) && ( 'standard' !== $form_name ) ) {
     968                        $form_names[] = $form_name;
     969                    }
     970                }
     971            }
    605972        } else {
    606             // Fallback: at least keep content resolved by BFB (you already have this method).
    607             if ( method_exists( 'WPBC_BFB_Booking_Data_Content_Resolver', 'maybe_override_booking_form_show_by_bfb' ) ) {
    608                 $pair['content'] = WPBC_BFB_Booking_Data_Content_Resolver::maybe_override_booking_form_show_by_bfb(
    609                     $pair['content'],
    610                     (int) $resource_id,
    611                     (string) $form_name,
    612                     '',
    613                     (is_array( $ctx ) ? $ctx : array())
    614                 );
    615             }
    616         }
    617     }
    618 
    619     // Normalize keys.
    620     if ( ! isset( $pair['form'] ) ) {
    621         $pair['form'] = '';
    622     }
    623     if ( ! isset( $pair['content'] ) ) {
    624         $pair['content'] = '';
    625     }
    626 
    627     $pair['form']    = (string) $pair['form'];
    628     $pair['content'] = (string) $pair['content'];
    629 
    630     return $pair;
    631 }
    632 
    633 /**
    634  * Get arr   of all Fields Names    from  all booking forms  (including custom)
    635  *
    636  * @return array   = [
    637                          0: [  name = "standard",  num =  8,  listing = [ ... ]    ],
    638                          1: [
    639                               name = "minimal"
    640                               num = 7
    641                               listing = [
    642                                            labels = [
    643                                                         0 = " adults"
    644                                                         1 = " children"
    645                                                         2 = " infants"
    646                                                         3 = " gender"
    647                                                         4 = " full_name"
    648                                                         5 = " email"
    649                                                         6 = " phone"
    650                                            fields = {array[7]}
    651                                                         0 = " adults"
    652                                                         1 = " children"
    653                                                         2 = " infants"
    654                                                         3 = " gender"
    655                                                         4 = " full_name"
    656                                                         5 = " email"
    657                                                         6 = " phone"
    658                                            fields_type = {array[7]}
    659                                                         0 = "select"
    660                                                         1 = "select"
    661                                                         2 = "select"
    662                                                         3 = "radio"
    663                                                         4 = "text"
    664                                                         5 = "email"
    665                                                         6 = "text"
    666                                         ]
    667                             ]
    668                          2: [], ...
    669  *                   ]
    670  */
    671 function wpbc_get__in_all_forms__field_names_arr() {
    672 
    673     $booking_form_fields_arr   = array();
    674     $ctx = wpbc_get_request_form_context();
    675 
    676     $ctx['form_status'] = 'published';
    677 
    678     $pair = wpbc_get__booking_form_pair__for_field_names_listing( 1, 'standard', $ctx );
    679 
    680     $booking_form_fields_arr[] = array(
    681         'name'    => 'standard',
    682         'form'    => $pair['form'],
    683         'content' => $pair['content'],
    684     );
    685 
    686     /**
    687      * Get custom booking form configurations: [
    688      *                                            [ name = "minimal",
    689      *                                              form = "[calendar]...",
    690      *                                              content = "<div class="payment-content-form"> [name] ..."
    691      *                                            ],
    692      *                                            ...
    693      *                                         ]
    694      */
    695     $is_can = apply_bk_filter( 'multiuser_is_user_can_be_here', true, 'only_super_admin' );
    696     if ( ( $is_can ) || ( get_bk_option( 'booking_is_custom_forms_for_regular_users' ) === 'On' ) ) {
    697         $booking_forms_extended = get_bk_option( 'booking_forms_extended' );
    698         $booking_forms_extended = maybe_unserialize( $booking_forms_extended );
    699         if (  false !== $booking_forms_extended ) {
    700             foreach ( $booking_forms_extended as $form_extended ) {
    701                 $booking_form_fields_arr[] = $form_extended;
    702             }
    703         }
    704     }
    705 
     973
     974            // Fallback to legacy list only if helper is unavailable.
     975            $is_can = apply_bk_filter( 'multiuser_is_user_can_be_here', true, 'only_super_admin' );
     976
     977            if ( ( $is_can ) || ( get_bk_option( 'booking_is_custom_forms_for_regular_users' ) === 'On' ) ) {
     978
     979                $booking_forms_extended = get_bk_option( 'booking_forms_extended' );
     980                $booking_forms_extended = maybe_unserialize( $booking_forms_extended );
     981
     982                if ( is_array( $booking_forms_extended ) ) {
     983                    foreach ( $booking_forms_extended as $form_extended_key => $form_extended ) {
     984
     985                        $form_name = '';
     986
     987                        if ( is_array( $form_extended ) && ! empty( $form_extended['name'] ) ) {
     988                            $form_name = sanitize_text_field( (string) $form_extended['name'] );
     989                        } elseif ( is_string( $form_extended_key ) ) {
     990                            $form_name = sanitize_text_field( (string) $form_extended_key );
     991                        }
     992
     993                        if ( ( '' !== $form_name ) && ( 'standard' !== $form_name ) ) {
     994                            $form_names[] = $form_name;
     995                        }
     996                    }
     997                }
     998            }
     999        }
     1000
     1001        $form_names = array_values( array_unique( $form_names ) );
     1002
     1003        foreach ( $form_names as $form_name ) {
     1004
     1005            $pair = wpbc_get__booking_form_pair__for_field_names_listing(
     1006                wpbc_get_default_resource(),
     1007                $form_name,
     1008                $ctx
     1009            );
     1010
     1011            $booking_form_fields_arr[] = array(
     1012                'name'    => $form_name,
     1013                'form'    => $pair['form'],
     1014                'content' => $pair['content'],
     1015            );
     1016        }
     1017    }
     1018
     1019    // ---------------------------------------------------------------------
     1020    // Common parser for both legacy and BFB mode.
     1021    // ---------------------------------------------------------------------
    7061022    foreach ( $booking_form_fields_arr as $form_key => $booking_form_element ) {
    7071023
    708         $booking_form = $booking_form_element['form'];
    709 
    710         $types = 'text[*]?|email[*]?|time[*]?|textarea[*]?|select[*]?|selectbox[*]?|checkbox[*]?|radio|acceptance|captchac|captchar|file[*]?|quiz';
    711         $regex = '%\[\s*(' . $types . ')(\s+[a-zA-Z][0-9a-zA-Z:._-]*)([-0-9a-zA-Z:#_/|\s]*)?((?:\s*(?:"[^"]*"|\'[^\']*\'))*)?\s*\]%';
     1024        $booking_form = isset( $booking_form_element['form'] ) ? (string) $booking_form_element['form'] : '';
     1025
     1026        $types  = 'text[*]?|email[*]?|time[*]?|textarea[*]?|select[*]?|selectbox[*]?|checkbox[*]?|radio|acceptance|captchac|captchar|file[*]?|quiz';
     1027        $regex  = '%\[\s*(' . $types . ')(\s+[a-zA-Z][0-9a-zA-Z:._-]*)([-0-9a-zA-Z:#_/|\s]*)?((?:\s*(?:"[^"]*"|\'[^\']*\'))*)?\s*\]%';
    7121028        $regex2 = '%\[\s*(country[*]?|starttime[*]?|endtime[*]?)(\s*[a-zA-Z]*[0-9a-zA-Z:._-]*)([-0-9a-zA-Z:#_/|\s]*)*((?:\s*(?:"[^"]*"|\'[^\']*\'))*)?\s*\]%';
    713         $fields_count = preg_match_all($regex, $booking_form, $fields_matches) ;
    714         $fields_count2 = preg_match_all($regex2, $booking_form, $fields_matches2) ;
    715 
    716         //Gathering Together 2 arrays $fields_matches  and $fields_matches2
    717         foreach ($fields_matches2 as $key => $value) {
    718             if ($key == 2) $value = $fields_matches2[1];
    719             foreach ($value as $v) {
    720                 $fields_matches[$key][count($fields_matches[$key])]  = $v;
    721             }
    722         }
     1029
     1030        $fields_matches  = array();
     1031        $fields_matches2 = array();
     1032
     1033        $fields_count  = preg_match_all( $regex, $booking_form, $fields_matches );
     1034        $fields_count2 = preg_match_all( $regex2, $booking_form, $fields_matches2 );
     1035
     1036        foreach ( $fields_matches2 as $key => $value ) {
     1037
     1038            if ( 2 === (int) $key ) {
     1039                $value = $fields_matches2[1];
     1040            }
     1041
     1042            if ( ! isset( $fields_matches[ $key ] ) || ! is_array( $fields_matches[ $key ] ) ) {
     1043                $fields_matches[ $key ] = array();
     1044            }
     1045
     1046            foreach ( $value as $single_value ) {
     1047                $fields_matches[ $key ][] = $single_value;
     1048            }
     1049        }
     1050
    7231051        $fields_count += $fields_count2;
    7241052
    7251053        $booking_form_fields_arr[ $form_key ]['num']     = $fields_count;
    726         $booking_form_fields_arr[ $form_key ]['listing'] = array();                //$fields_matches;
     1054        $booking_form_fields_arr[ $form_key ]['listing'] = array();
     1055
     1056        if ( ! isset( $fields_matches[1] ) ) {
     1057            $fields_matches[1] = array();
     1058        }
     1059        if ( ! isset( $fields_matches[2] ) ) {
     1060            $fields_matches[2] = array();
     1061        }
    7271062
    7281063        $fields_matches[1] = array_map( 'trim', $fields_matches[1] );
     
    7301065
    7311066        $booking_form_fields_arr[ $form_key ]['listing']['labels'] = array_map( 'ucfirst', $fields_matches[2] );
    732         $booking_form_fields_arr[ $form_key ]['listing']['fields'] = $fields_matches[2] ;
     1067        $booking_form_fields_arr[ $form_key ]['listing']['fields'] = $fields_matches[2];
    7331068
    7341069        foreach ( $fields_matches[1] as $key_fm => $value_fm ) {
     
    7381073        $booking_form_fields_arr[ $form_key ]['listing']['fields_type'] = $fields_matches[1];
    7391074
    740         // Reset
    7411075        unset( $booking_form_fields_arr[ $form_key ]['form'] );
    7421076        unset( $booking_form_fields_arr[ $form_key ]['content'] );
     
    7441078
    7451079    return $booking_form_fields_arr;
     1080}
     1081
     1082/**
     1083 * Get options for billing field assignment from all available booking forms.
     1084 *
     1085 * Important:
     1086 * - Collect fields from standard, legacy custom, and BFB forms.
     1087 * - Keep option VALUE as plain field name for backwards compatibility.
     1088 * - Use the first found label as option title.
     1089 *
     1090 * @return array
     1091 */
     1092function wpbc_get__field_options__for_billing_assignment() {
     1093
     1094    $field_options = array(
     1095        '' => __( 'Please select', 'booking' ),
     1096    );
     1097
     1098    $booking_forms = wpbc_get__in_all_forms__field_names_arr();
     1099
     1100    if ( empty( $booking_forms ) || ! is_array( $booking_forms ) ) {
     1101        return $field_options;
     1102    }
     1103
     1104    $unique_fields = array();
     1105
     1106    foreach ( $booking_forms as $single_booking_form ) {
     1107
     1108        if (
     1109            empty( $single_booking_form['listing'] )
     1110            || ! is_array( $single_booking_form['listing'] )
     1111            || empty( $single_booking_form['listing']['fields'] )
     1112            || ! is_array( $single_booking_form['listing']['fields'] )
     1113        ) {
     1114            continue;
     1115        }
     1116
     1117        $field_labels = array();
     1118
     1119        if (
     1120            isset( $single_booking_form['listing']['labels'] )
     1121            && is_array( $single_booking_form['listing']['labels'] )
     1122        ) {
     1123            $field_labels = $single_booking_form['listing']['labels'];
     1124        }
     1125
     1126        foreach ( $single_booking_form['listing']['fields'] as $field_index => $field_name ) {
     1127
     1128            $field_name = trim( (string) $field_name );
     1129
     1130            if ( '' === $field_name ) {
     1131                continue;
     1132            }
     1133
     1134            // Keep first found label/value pair.
     1135            if ( isset( $unique_fields[ $field_name ] ) ) {
     1136                continue;
     1137            }
     1138
     1139            $field_label = isset( $field_labels[ $field_index ] ) ? trim( (string) $field_labels[ $field_index ] ) : '';
     1140
     1141            if ( '' === $field_label ) {
     1142                $field_label = $field_name;
     1143            }
     1144
     1145            $unique_fields[ $field_name ] = $field_label;
     1146        }
     1147    }
     1148
     1149    foreach ( $unique_fields as $field_name => $field_label ) {
     1150        $field_options[ $field_name ] = $field_label;
     1151    }
     1152
     1153    return $field_options;
    7461154}
    7471155
  • booking/trunk/includes/_functions/str_regex.php

    r3291612 r3492420  
    99 * @link https://wpbookingcalendar.com/
    1010 * @email info@wpbookingcalendar.com
     11 *
     12 * @file ../includes/_functions/str_regex.php
    1113 *
    1214 * @modified 2024-05-14
  • booking/trunk/includes/page-form-builder/assets/template-records/technical_support_form.php

    r3488732 r3492420  
    2222    stripcslashes(
    2323<<<'WPBC_BFB_TEMPLATE_SETTINGS'
    24 {\"options\":{\"booking_form_theme\":\"\",\"booking_form_layout_width\":\"100%\",\"booking_type_of_day_selections\":\"single\"},\"css_vars\":[],\"bfb_options\":{\"advanced_mode_source\":\"builder\"}}
     24{\"options\":{\"booking_form_theme\":\"\",\"booking_form_layout_width\":\"100%\",\"booking_type_of_day_selections\":\"\"},\"css_vars\":[],\"bfb_options\":{\"advanced_mode_source\":\"builder\"}}
    2525WPBC_BFB_TEMPLATE_SETTINGS
    2626    )
  • booking/trunk/includes/page-form-builder/assets/template-records/time_slots_20_min_2_steps_wizard.php

    r3488732 r3492420  
    2222    stripcslashes(
    2323<<<'WPBC_BFB_TEMPLATE_SETTINGS'
    24 {\"options\":{\"booking_form_theme\":\"\",\"booking_form_layout_width\":\"100%\",\"booking_type_of_day_selections\":\"single\"},\"css_vars\":[],\"bfb_options\":{\"advanced_mode_source\":\"builder\"}}
     24{\"options\":{\"booking_form_theme\":\"\",\"booking_form_layout_width\":\"100%\",\"booking_type_of_day_selections\":\"\"},\"css_vars\":[],\"bfb_options\":{\"advanced_mode_source\":\"builder\"}}
    2525WPBC_BFB_TEMPLATE_SETTINGS
    2626    )
  • booking/trunk/includes/page-form-builder/assets/template-records/time_slots_30_min_2_steps_wizard.php

    r3488732 r3492420  
    2222    stripcslashes(
    2323<<<'WPBC_BFB_TEMPLATE_SETTINGS'
    24 {\"options\":{\"booking_form_theme\":\"\",\"booking_form_layout_width\":\"100%\",\"booking_type_of_day_selections\":\"single\"},\"css_vars\":[],\"bfb_options\":{\"advanced_mode_source\":\"builder\"}}
     24{\"options\":{\"booking_form_theme\":\"\",\"booking_form_layout_width\":\"100%\",\"booking_type_of_day_selections\":\"\"},\"css_vars\":[],\"bfb_options\":{\"advanced_mode_source\":\"builder\"}}
    2525WPBC_BFB_TEMPLATE_SETTINGS
    2626    )
  • booking/trunk/includes/page-form-builder/assets/template-records/time_slots_start_duration_times_selection.php

    r3488732 r3492420  
    2222    stripcslashes(
    2323<<<'WPBC_BFB_TEMPLATE_SETTINGS'
    24 {\"options\":{\"booking_form_theme\":\"\",\"booking_form_layout_width\":\"100%\",\"booking_type_of_day_selections\":\"single\"},\"css_vars\":[],\"bfb_options\":{\"advanced_mode_source\":\"builder\"}}
     24{\"options\":{\"booking_form_theme\":\"\",\"booking_form_layout_width\":\"100%\",\"booking_type_of_day_selections\":\"\"},\"css_vars\":[],\"bfb_options\":{\"advanced_mode_source\":\"builder\"}}
    2525WPBC_BFB_TEMPLATE_SETTINGS
    2626    )
  • booking/trunk/includes/page-form-builder/assets/template-records/time_slots_start_end_times_1_hour_selection.php

    r3488732 r3492420  
    2222    stripcslashes(
    2323<<<'WPBC_BFB_TEMPLATE_SETTINGS'
    24 {\"options\":{\"booking_form_theme\":\"\",\"booking_form_layout_width\":\"100%\",\"booking_type_of_day_selections\":\"single\"},\"css_vars\":[],\"bfb_options\":{\"advanced_mode_source\":\"builder\"}}
     24{\"options\":{\"booking_form_theme\":\"\",\"booking_form_layout_width\":\"100%\",\"booking_type_of_day_selections\":\"\"},\"css_vars\":[],\"bfb_options\":{\"advanced_mode_source\":\"builder\"}}
    2525WPBC_BFB_TEMPLATE_SETTINGS
    2626    )
  • booking/trunk/readme.txt

    r3491856 r3492420  
    66Requires PHP: 5.6
    77Tested up to: 7.0
    8 Stable tag: 10.15.3
     8Stable tag: 10.15.4
    99License: GPLv2 or later
    1010License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    1414== Description ==
    1515
    16 = Booking Calendar - WordPress Booking Plugin for Appointments, Reservations, Rentals, and Events =
     16= Booking Calendar - Booking Plugin for Appointments, Reservations, Rentals, Events =
    1717**WP Booking Calendar** is a flexible **WordPress booking plugin** for **appointments**, **reservations**, **rentals**, and **events**. Add a responsive **availability calendar** and **booking form** to your website, accept **online bookings**, and manage them from a modern admin panel.
    1818
     
    5454This new functionality brings a more modern, user-friendly, and flexible way to create forms in Booking Calendar, making form setup faster, clearer, and much more convenient for website owners.
    5555
    56 > <strong>Full Day Bookings - Drag and Drop Booking Form Builder</strong><br />
    57 > Easily configure Booking Calendar for full-day bookings with the new Drag and Drop Booking Form Builder. The new Booking Calendar Form Builder makes it much easier to create flexible booking forms without manually editing form code. It is a simple and visual way to build booking forms for different use cases directly inside WordPress.
    58 
    59 https://www.youtube.com/watch?v=n_svjKULkc0
    60 
    61 > <strong>Create a Time Slots Booking Form in minutes with the new Booking Calendar Form Builder.</strong><br />
    62 
    63 https://www.youtube.com/watch?v=6hV11Cfc61Q
    64 
    65 = Setup Wizard! =
    66 > <strong>Easy Time Appointments Configuration for your Bookings</strong><br />
    67 > Set up **appointment booking system** in less than 2.5 minutes. Designed with a user-friendly flow, the wizard takes you step-by-step through key settings, including booking type selection, calendar appearance, availability preferences, and more. This step-by-step setup helps you get your booking system ready for your business quickly and easily.
    68 
    69 https://www.youtube.com/watch?v=GYJWZJBFwXw
    70 
    71 > <strong>Changeover Multi-Day Bookings - Setup Wizard (Pro)</strong><br />
    72 > Configure multi-day bookings with specific check-in and check-out days, clearly marked with diagonal or vertical lines. Perfect for bookings that require split days. <br>**Available Pro versions**.
    73 
    74 https://www.youtube.com/watch?v=uCQ9JmHR8w4
    75 
    7656= Perfect solution for any booking logic =
    7757
     
    9373- Or any other service where booking for a specific time is required
    9474
    95 ### Simple steps to get started
    96 
    97 = 1. Add booking form or availability calendar to your page =
     75= Full Day Bookings - Drag and Drop Booking Form Builder =
     76Easily configure Booking Calendar for full-day bookings with the new Drag and Drop Booking Form Builder. The new Booking Calendar Form Builder makes it much easier to create flexible booking forms without manually editing form code. It is a simple and visual way to build booking forms for different use cases directly inside WordPress.
     77
     78https://www.youtube.com/watch?v=n_svjKULkc0
     79
     80= Appointment Forms with Time Slots or Start Time + Service Duration Selection =
     81Create a time-slot booking form in just a few minutes with the new Booking Calendar Form Builder. Visually add the calendar, time fields, and contact fields, adjust the layout, and preview changes instantly — without manually editing form code.
     82
     83https://www.youtube.com/watch?v=6hV11Cfc61Q
     84
     85= Changeover Multi-Day Bookings - Setup Wizard (Pro) =
     86Configure multi-day bookings with specific check-in and check-out days, clearly marked with diagonal or vertical lines. Perfect for bookings that require split days. <br>**Available Pro versions**.
     87
     88https://www.youtube.com/watch?v=uCQ9JmHR8w4
     89
     90== Installation ==
     91
     92Installing the plugin is easy. Just follow one of the following methods:
     93
     94= Install Booking Calendar from within Wordpress =
     95
     961. Visit the plugins page within your dashboard and select ‘Add New’
     972. Search for "Booking Calendar by oplugins"
     983. Activate Booking Calendar from your Plugins page
     994. You're done!
     100
     101
     102= Install Booking Calendar Manually =
     103
     1041. From the dashboard of your site, navigate to Plugins --> Add New.
     1052. Select the Upload option and hit "Choose File."
     1063. When the popup appears select the booking.zip or booking-x.x.zip file from your desktop. (The 'x.x' will change depending on the current version number).
     1074. Follow the on-screen instructions and wait as the upload completes.
     1085. When it's finished, activate the plugin via the prompt. A message will show confirming activation was successful.
     109
     110That's it! Just configure your settings and [insert booking form shortcode](https://wpbookingcalendar.com/faq/insert-booking-calendar-into-page/ ) into a page, and you're on your way to receive the bookings. Need help getting things started? Check out our [FAQ](https://wpbookingcalendar.com/faq/) and [video guides](https://wpbookingcalendar.com/help/) for help with settings and features.
     111
     112== Frequently Asked Questions ==
     113
     114Please see [FAQ](https://wpbookingcalendar.com/faq/).
     115
     116= All you need to know about booking process =
     117
     118**Step 1: Select your desired date(s)**
     119Customers can select the date(s) they would like to book. The **Booking Calendar** plugin provides an easy-to-use calendar system that displays the availability of your property or service for those dates.
     120
     121**Step 2: Select a time-slot (optional)**
     122If you offer appointments or reservations at specific times, you can configure the booking form to allow customers to select an available time-slot. To learn how to set it up, please [watch this video](https://youtu.be/-pOTMiyp6Q8?t=28s "Video guide how to configure time slots in Booking Calendar Free version").
     123
     124**Step 3: Fill in Booking Form Fields**
     125The form will ask for information such as your name, contact information, and other details needed to approve the booking. The booking form fields are customizable, allowing you to configure fields required for the booking.
     126
     127**Step 4: Submit your booking and Receive Notification of New Booking**
     128After filling out the booking form, customers can submit the booking. The **Booking Calendar** plugin will notify the administrator about the new booking and send a confirmation email to customers that their booking has been received.
     129
     130**Step 5: Manage Bookings**
     131Administrators can manage all reservations from the modern and easy-to-use admin booking panel. Easily find the required bookings, check the booking details, and modify the booking if needed, then approve or decline this reservation. Customers will receive an email confirmation about the approval or cancellation of their booking.
     132
     133= Simple steps to get started =
     134**1. Add booking form or availability calendar to your page**
    98135Easily insert the booking form on any page of your website using WordPress blocks or Booking Calendar widgets for sidebars or configure shortcode block in page builders like Elementor. Read more [here](https://wpbookingcalendar.com/faq/insert-booking-calendar-into-page/ "How to insert the booking form or availability calendar into the page?").
    99136
    100 = 2. Set initial unavailable days with just few clicks =
     137**2. Set initial unavailable days with just few clicks**
    101138You can **define days availability** in just a 3 mouse clicks at Booking > Availability page. Simply select a range of days on the calendar, choose 'available' or 'unavailable' status, and apply. It’s that simple!
    102139
    103 = 3. Configure booking form, email templates and other settings =
     140**3. Configure booking form, email templates and other settings**
    104141Easily **customize** your **booking form** fields and add **[time slots](https://youtu.be/-pOTMiyp6Q8?t=28s "Video guide how to configure time slots in Booking Calendar Free version")** if needed. Configure **email** notifications and other settings such as the **calendar** appearance, booking admin panel functionality, and more...
    105142
    106 = 4. Receive notifications and manage bookings =
     143**4. Receive notifications and manage bookings**
    107144Get notified about a **new appointments** and manage them in a modern admin panel. **Approve**, **decline**, or **edit** specific bookings. Plus, you can get a complete picture of your schedule with the **calendar overview** in **day**, **week**, or **month** view mode.
    108145
    109 = 5. Configure syncing of bookings with other services =
    110 **Import** your **Google Calendar** events or make **2 ways sync** of your events by using **.ics feeds** with various services such as Airbnb, Booking.com, VRBO, HomeAway, TripAdvisor, FlipKey, and more... Thanks to native integration with [Booking Manager](https://wordpress.org/plugins/booking-manager/) plugin.
    111 
    112 ### How it works?
    113 
    114 - **Step 1:** Visitor select desired date(s) in calendar
    115 - **Step 2:** Visitor selects a time-slot (optional)
    116 - **Step 3:** Visitor fills in Booking Form and submits it
    117 - **Step 4:** You receive a notification and manage the booking
    118 
    119 ### Awesome features:
    120 
    121 = New =
    122 Super **easy set available/unavailable dates** in calendar with just three mouse clicks.
    123 
    124 In Booking Calendar you can define days as available or unavailable in just a few clicks. Simply select a range of days on the calendar, choose 'available' or 'unavailable' status, and apply. It's that simple!
    125 
    126 = General =
     146**5. Configure syncing of bookings with other services**
     147Import your **Google Calendar** events or make **2 ways sync** of your events by using **.ics feeds** with various services such as Airbnb, Booking.com, VRBO, HomeAway, TripAdvisor, FlipKey, and more... Thanks to native integration with [Booking Manager](https://wordpress.org/plugins/booking-manager/) plugin.
     148
     149= Awesome features: =
     150
     151**Setup Wizard!**
     152- Easy Time Appointments Configuration for your Bookings
     153- Set up **appointment booking system** in less than 2.5 minutes. Designed with a user-friendly flow, the wizard takes you step-by-step through key settings, including booking type selection, calendar appearance, availability preferences, and more. This step-by-step setup helps you get your booking system ready for your business quickly and easily.
     154
     155https://www.youtube.com/watch?v=GYJWZJBFwXw
     156
     157**Set Days Availability**
     158- Super **easy set available/unavailable dates** in calendar with just three mouse clicks.
     159- In Booking Calendar you can define days as available or unavailable in just a few clicks. Simply select a range of days on the calendar, choose 'available' or 'unavailable' status, and apply. It's that simple!
     160
     161**General**
    127162- **Modern** and **easy to use** interface.
    128163- The plugin is designed to be a suitable for a vast array of businesses.
     
    131166- **Multi language** support. Check all available languages at [this page](https://wordpress.org/plugins/booking/#support%20languages%20%28local%29 "Translations").
    132167
    133 = Easy to start using =
    134 Booking Calendar is an easy solution to start receiving bookings.
    135 You can quickly [add the booking calendar](https://wpbookingcalendar.com/faq/insert-booking-calendar-into-page/) to your posts or pages using WordPress blocks or shortcodes. Additionally, you can add the booking calendar as a widget to your site's sidebar.
    136 Most of the settings come with predefined values and descriptions.
    137 
    138 = Bookings =
     168**Easy to start using**
     169- Booking Calendar is an easy solution to start receiving bookings.
     170- You can quickly [add the booking calendar](https://wpbookingcalendar.com/faq/insert-booking-calendar-into-page/) to your posts or pages using WordPress blocks or shortcodes. Additionally, you can add the booking calendar as a widget to your site's sidebar.
     171- Most of the settings come with predefined values and descriptions.
     172
     173**Bookings**
    139174- **Prevention of double bookings** - one booking per day or time slot.
    140175- Alternatively, you can allow **unlimited bookings for the same date** and time within the same calendar.
    141176- You can enable **pending bookings as available** in the calendar, which lets you receive multiple bookings for the same date until you manually approve one of them. You can receive as many bookings as you need to and stop receiving bookings on specific dates once you have approved a booking.
    142177
    143 = Timeslots bookings =
    144 **[Time slot bookings](https://youtu.be/-pOTMiyp6Q8?t=28s "Video guide how to configure time slots in Booking Calendar Free version")** are available in the Booking Calendar Free version, which allows you to receive bookings for available time-slots during a selected day. Customers can select time slots either in a time picker or from a dropdown list, depending on your settings at Settings General page in "Time Slots" section.
    145 
    146 = Calendar =
    147 - Select a **calendar skin** that matches your website design.
    148 - Or customize the calendar colors by [editing the CSS](https://wpbookingcalendar.com/faq/change-skin-and-colors/) styles.
    149 - Choose to display [one or several months](https://wpbookingcalendar.com/faq/shortcode-booking-form/#booking-options) in the calendar view.
    150 - Easily set the width of the calendar and the number of months in a row, such as [3x2 months](https://wpbookingcalendar.com/faq/shortcode-booking-form/#booking-options).
    151 - Choose between **single** day or **multiple days** selection mode.
    152 - Set the number of unavailable days in the calendar, starting from today.
    153 - Specify particular weekdays as unavailable.
    154 - Show a legend on the calendar to help visitors understand the status of each day.
    155 
    156 = Booking Form =
     178**Timeslots bookings**
     179- [Time slot bookings](https://youtu.be/-pOTMiyp6Q8?t=28s "Video guide how to configure time slots in Booking Calendar Free version")** are available in the Booking Calendar Free version, which allows you to receive bookings for available time-slots during a selected day. Customers can select time slots either in a time picker or from a dropdown list, depending on your settings at Settings General page in "Time Slots" section.
     180
     181**Calendar**
     182 Select a **calendar skin** that matches your website design.<br>
     183 Or customize the calendar colors by [editing the CSS](https://wpbookingcalendar.com/faq/change-skin-and-colors/) styles.<br>
     184 Choose to display [one or several months](https://wpbookingcalendar.com/faq/shortcode-booking-form/#booking-options) in the calendar view.<br>
     185 Easily set the width of the calendar and the number of months in a row, such as [3x2 months](https://wpbookingcalendar.com/faq/shortcode-booking-form/#booking-options).<br>
     186 Choose between **single** day or **multiple days** selection mode.<br>
     187 Set the number of unavailable days in the calendar, starting from today.<br>
     188 Specify particular weekdays as unavailable.<br>
     189 Show a legend on the calendar to help visitors understand the status of each day.<br>
     190
     191**Booking Form**
    157192Easily customize your booking form fields to capture all the necessary information for each booking. Choose which fields are required and which are optional, and customize field labels as needed. Plus, the booking form includes **CAPTCHA** support to prevent spam submissions.
    158193
    159 = Timeline =
     194**Timeline**
    160195[Timeline view](https://wpbookingcalendar.com/faq/shortcode-timeline/) allows you to display all your bookings in a yearly, monthly, or daily view on the front-end of your website, giving your visitors a quick and comprehensive overview of your schedule.
    161196
    162 = Booking Admin Panel =
     197**Booking Admin Panel**
    163198- Easily manage your bookings with a modern and clear [Booking Listing](https://ps.w.org/booking/assets/screenshot-03.gif?rev=2870020) panel or with the intuitive [Calendar Overview](https://ps.w.org/booking/assets/screenshot-04.png?rev=2870020) mode.
    164199- The [Booking Listing](https://ps.w.org/booking/assets/screenshot-03.gif?rev=2870020) makes it very simple to find the required reservations. It provides searching by different criteria and immediate results based on keywords.
     
    168203- Get the number of new bookings on the **booking dashboard section**.
    169204
    170 = Google Calendar Integration =
     205**Google Calendar Integration**
    171206- [Import events](https://wpbookingcalendar.com/faq/import-gc-events/) from your **Google Calendar** to the Booking Calendar plugin.
    172207- With just one click, **add bookings to Google Calendar** from the Booking Listing page using export button near each booking(s).
    173208
    174 = Sync bookings =
     209**Sync bookings**
    175210- Easily **import and export** events using .ics feeds or files with native integration with our [Booking Manager](https://wordpress.org/plugins/booking-manager/) plugin.
    176211- **[Import events](https://wpbookingcalendar.com/faq/#sync)** from various sources, such as Airbnb, Booking.com, HomeAway, TripAdvisor, VRBO, FlipKey, and any other calendar that uses the .ics format.
     
    178213- **[Export bookings](https://wpbookingcalendar.com/faq/#sync)** by configuring custom URL for your.ics feed. This feed can then be imported into services that use the .ics (iCal) format, such as Google Calendar or Airbnb, etc...
    179214
    180 = Email Notifications =
     215**Email Notifications**
    181216Configure email confirmation to be sent to the site administrator and visitors for specific booking actions, such as new booking creation, approval or decline of bookings. You can customize the content and format of the emails, and also change the administrator email address to receive notifications.
    182217
    183 = Other settings =
    184 - Customizable **date format** for your bookings.
    185 - **Restriction of access** to plugin menus for standard WordPress user roles.
    186 
     218**Other settings**
     219 Customizable **date format** for your bookings.<br>
     220 **Restriction of access** to plugin menus for standard WordPress user roles.<br>
     221<br>
    187222And **much more**... Check ton of features in [premium versions](https://wpbookingcalendar.com/features/ "Booking Calendar Features list") of plugin.
    188223
    189 ### Premium Features in paid versions
    190 
    191 = Booking Calendar Personal (or higher versions) =
     224
     225= Premium Features in paid versions =
     226
     227**Booking Calendar Personal (or higher versions)**
    192228- [Multiple booking resources (calendars)](https://wpbookingcalendar.com/features/#booking-resources) - create an unlimited number of booking resources (calendars), which can be your services, properties, or any other items that can be booked by visitors in separate unique calendars.
    193229- [Advanced configuration of booking form and emails](https://wpbookingcalendar.com/features/#booking-form) - fully customize the appearance of your booking form and email templates.
    194230- [Manage bookings](https://wpbookingcalendar.com/features/#manage-bookings) - perform various actions such as CSV export, adding notes, editing, duplicating, changing resources, and much more...
    195231
    196 = Booking Calendar Business Small (or higher versions) =
     232**Booking Calendar Business Small (or higher versions)**
    197233- [Online Payments](https://wpbookingcalendar.com/features/#payments) - accept online payments for your bookings, with support for various payment gateways like **Stripe, PayPal, Authorize.Net, Redsys**, and more.
    198234- [Changeover Days](https://wpbookingcalendar.com/features/#change-over-days) - enable **split bookings** marked by vertical or diagonal lines, allowing visitors to check out and check in on the same date.
     
    201237- [Advanced Hourly Bookings](https://wpbookingcalendar.com/features/#times) - increase the flexibility of your Booking Calendar by allowing visitors to book specific start and end times or duration of time, ensuring precise scheduling for your services.
    202238
    203 =  Booking Calendar Business Medium (or higher versions) =
     239**Booking Calendar Business Medium (or higher versions)**
    204240- [Seasonal Prices](https://wpbookingcalendar.com/features/#rates) - customize the daily cost (rates) for different seasons or week days with fixed costs per day or as a percentage from original daily cost.
    205241- [Multi-Day Pricing](https://wpbookingcalendar.com/features/#valuation-days) - set different cost of booking based on the number of selected days, and the ability to apply these costs only if the "Check In" day falls within a specific season.
     
    215251- [Unavailable time before or after a booking](https://wpbookingcalendar.com/features/#unavailable-time-after-before-booking) - setting the number of minutes, hours, or days needed for cleaning or other services, applicable to bookings with time slots or change-over days feature.
    216252
    217 =  Booking Calendar Business Large (or higher versions) =
     253**Booking Calendar Business Large (or higher versions)**
    218254- [Capacity and Availability](https://wpbookingcalendar.com/features/#capacity) - set the  the maximum number of bookings that can be made per full day or time slots  in calendar, and ensure that dates in the calendar are only available until the capacity is reached.
    219255- [Search Availability](https://wpbookingcalendar.com/features/#search) - allows your website visitors to quickly search for available booking resources such as properties or services by entering check-in/out dates and other criteria like the number of guests or specific amenities.
     
    221257- [Auto-Cancel Pending Bookings](https://wpbookingcalendar.com/features/#pending-available) - enable automatic cancellation of pending bookings for specific dates when you approve booking for the same resource.
    222258
    223 =  Booking Calendar MultiUser version =
     259**Booking Calendar MultiUser version**
    224260- [MultiUser Booking Admin Panels](https://wpbookingcalendar.com/features/#multiuser) - enable each registered WordPress user to have their own individual booking admin panel, where they can see and manage only their own bookings, resources, and settings. This includes the ability to configure their own booking form, receive notifications to own separate emails, and activate payment gateways for their own payment accounts.
    225 
    226 == Installation ==
    227 
    228 Installing the plugin is easy. Just follow one of the following methods:
    229 
    230 = Install Booking Calendar from within Wordpress =
    231 
    232 1. Visit the plugins page within your dashboard and select ‘Add New’
    233 2. Search for "Booking Calendar by oplugins"
    234 3. Activate Booking Calendar from your Plugins page
    235 4. You're done!
    236 
    237 
    238 = Install Booking Calendar Manually =
    239 
    240 1. From the dashboard of your site, navigate to Plugins --> Add New.
    241 2. Select the Upload option and hit "Choose File."
    242 3. When the popup appears select the booking.zip or booking-x.x.zip file from your desktop. (The 'x.x' will change depending on the current version number).
    243 4. Follow the on-screen instructions and wait as the upload completes.
    244 5. When it's finished, activate the plugin via the prompt. A message will show confirming activation was successful.
    245 
    246 That's it! Just configure your settings and [insert booking form shortcode](https://wpbookingcalendar.com/faq/insert-booking-calendar-into-page/ ) into a page, and you're on your way to receive the bookings. Need help getting things started? Check out our [FAQ](https://wpbookingcalendar.com/faq/) and [video guides](https://wpbookingcalendar.com/help/) for help with settings and features.
    247 
    248 == Frequently Asked Questions ==
    249 
    250 Please see [FAQ](https://wpbookingcalendar.com/faq/).
    251 
    252 = All you need to know about booking process =
    253 
    254 **Step 1: Select your desired date(s)**
    255 Customers can select the date(s) they would like to book. The **Booking Calendar** plugin provides an easy-to-use calendar system that displays the availability of your property or service for those dates.
    256 
    257 **Step 2: Select a time-slot (optional)**
    258 If you offer appointments or reservations at specific times, you can configure the booking form to allow customers to select an available time-slot. To learn how to set it up, please [watch this video](https://youtu.be/-pOTMiyp6Q8?t=28s "Video guide how to configure time slots in Booking Calendar Free version").
    259 
    260 **Step 3: Fill in Booking Form Fields**
    261 The form will ask for information such as your name, contact information, and other details needed to approve the booking. The booking form fields are customizable, allowing you to configure fields required for the booking.
    262 
    263 **Step 4: Submit your booking and Receive Notification of New Booking**
    264 After filling out the booking form, customers can submit the booking. The **Booking Calendar** plugin will notify the administrator about the new booking and send a confirmation email to customers that their booking has been received.
    265 
    266 **Step 5: Manage Bookings**
    267 Administrators can manage all reservations from the modern and easy-to-use admin booking panel. Easily find the required bookings, check the booking details, and modify the booking if needed, then approve or decline this reservation. Customers will receive an email confirmation about the approval or cancellation of their booking.
    268261
    269262= Privacy Notices =
     
    316309
    317310If you have some questions, which you haven't found at [FAQ](https://wpbookingcalendar.com/faq/) you can post them at [technical help board](https://wpbookingcalendar.com/support/)
    318 = Video Tutorials =
    319 
    320 Please see [Video Guides](https://wpbookingcalendar.com/help/).
    321311
    322312
     
    333323
    334324== Changelog ==
     325= 10.15.4 =
     326- Changes in **all** versions:
     327    * **Fix**: Showing options for the "Booking Quantity Control" field,  regarding custom booking forms in the new Forms Builder. This fix related to  the  Booking Calendar Business Large or higher version. (10.15.4.1)
     328
    335329= 10.15.3 =
    336330- Changes in **all** versions:
  • booking/trunk/wpdev-booking.php

    r3491589 r3492420  
    88Text Domain: booking
    99Domain Path: /languages/
    10 Version: 10.15.3
     10Version: 10.15.4
    1111License: GPLv2 or later
    1212*/
     
    3535
    3636if ( ! defined( 'WP_BK_VERSION_NUM' ) ) {
    37     define( 'WP_BK_VERSION_NUM', '10.15.3' );
     37    define( 'WP_BK_VERSION_NUM', '10.15.4' );
    3838}
    3939if ( ! defined( 'WP_BK_MINOR_UPDATE' ) ) {
Note: See TracChangeset for help on using the changeset viewer.