← All changes
|
includes/_front_end/class-fe-render-form-body.php
+266
-114
11.2.1
→
11.9
View file →
| @@ -1,12 +1,12 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | /** |
| 3 | 3 | * Front-End Form Body Rendering |
| 4 | 4 | * |
| 5 | 5 | * - Calendar markup (or hidden selected-dates field) |
| 6 | - * - Form body source resolution (BFB / legacy / simple) | |
| 6 | + * - Form body source resolution (BFB) | |
| 7 | 7 | * - Legacy post-processing hooks (additional calendars, captcha, change-over times) |
| 8 | - * - Legacy wrapper (<form> container + nonce + hidden fields) | |
| 8 | + * - Shared wrapper (<form> container + nonce + hidden fields) | |
| 9 | 9 | * - Legacy inline scripts (duplicate-calendar warning, cost hints, autofill) |
| 10 | 10 | * |
| 11 | 11 | * @package Booking Calendar |
| 12 | 12 | * @since 11.0.x |
| @@ -19,9 +19,9 @@ | ||
| 19 | 19 | |
| 20 | 20 | /** |
| 21 | 21 | * Booking Form Body Renderer. |
| 22 | 22 | * |
| 23 | - * Orchestrates building of the booking form HTML while preserving legacy output and | |
| 23 | + * Orchestrates building of the booking form HTML while preserving output and | |
| 24 | 24 | * filter/action execution order. |
| 25 | 25 | * |
| 26 | 26 | * @since 11.0.x |
| 27 | 27 | */ |
| @@ -34,11 +34,9 @@ | ||
| 34 | 34 | * Expected flow: |
| 35 | 35 | * 1) Parse shortcode "options" into custom parameters (for BFB/simple form context). |
| 36 | 36 | * 2) Build calendar markup OR hidden textarea with preselected dates. |
| 37 | 37 | * 3) Resolve form body source: |
| 38 | - * - BFB source (if available) with filter override and shortcode-engine fallback. | |
| 39 | - * - Legacy booking form (personal.php). | |
| 40 | - * - Simple form fallback. | |
| 38 | + * - BFB source with filter override and shortcode-engine fallback. | |
| 41 | 39 | * 4) Post-process composed markup: |
| 42 | 40 | * - Insert calendar ([calendar] placeholder or prepend). |
| 43 | 41 | * - Replace additional calendars via legacy filter. |
| 44 | 42 | * - Replace [captcha] placeholder. |
| @@ -123,9 +121,35 @@ | ||
| 123 | 121 | |
| 124 | 122 | // 3. Postprocess Form Conent - regarding settings - e.g.: $source_res['bfb_settings'] = [ options = [ booking_form_theme = "wpbc_theme_dark_1", .... ], ... |
| 125 | 123 | $wrapped = apply_filters( 'wpbc_booking_form__wrapped_html__before_inline_scripts', $wrapped, $source_res['bfb_settings'], $resource_id, $custom_booking_form ); |
| 126 | 124 | |
| 127 | - $wrapped .= WPBC_FE_Inline_Scripts::collect( $resource_id ); | |
| 125 | + /** | |
| 126 | + * Filters whether the current booking form render should collect legacy | |
| 127 | + * page-level inline scripts. | |
| 128 | + * | |
| 129 | + * Request-local administration previews initialize their returned markup | |
| 130 | + * through an explicit bootstrap payload. They must not queue callbacks on | |
| 131 | + * the parent administration page because the preview form can be replaced | |
| 132 | + * before those callbacks run. | |
| 133 | + * | |
| 134 | + * @since 11.9.0 | |
| 135 | + * | |
| 136 | + * @param bool $should_collect Whether legacy inline scripts should be collected. | |
| 137 | + * @param int $resource_id Booking resource ID used by the rendered form. | |
| 138 | + * @param string $custom_booking_form Booking form slug requested by the renderer. | |
| 139 | + * @param string $form_status Normalized renderer status such as published or preview. | |
| 140 | + */ | |
| 141 | + $should_collect_inline_scripts = (bool) apply_filters( | |
| 142 | + 'wpbc_booking_form__should_collect_inline_scripts', | |
| 143 | + true, | |
| 144 | + $resource_id, | |
| 145 | + $custom_booking_form, | |
| 146 | + $form_status | |
| 147 | + ); | |
| 148 | + | |
| 149 | + if ( $should_collect_inline_scripts ) { | |
| 150 | + $wrapped .= WPBC_FE_Inline_Scripts::collect( $resource_id ); | |
| 151 | + } | |
| 128 | 152 | |
| 129 | 153 | // Info: Hook for addons. Postprocess Form Conent - regarding settings - e.g.: $source_res['bfb_settings'] = [ options = [ booking_form_theme = "wpbc_theme_dark_1", .... ], ... |
| 130 | 154 | $wrapped = apply_filters( 'wpbc_booking_form__wrapped_html__after_inline_scripts', $wrapped, $source_res['bfb_settings'], $resource_id, $custom_booking_form ); |
| 131 | 155 | |
| @@ -339,9 +363,9 @@ | ||
| 339 | 363 | } |
| 340 | 364 | |
| 341 | 365 | |
| 342 | 366 | /** |
| 343 | - * Return the booking form body HTML, choosing BFB source if available, else legacy. | |
| 367 | + * Return the booking form body HTML from BFB storage. | |
| 344 | 368 | * |
| 345 | 369 | * @param int $resource_id |
| 346 | 370 | * @param string $custom_booking_form |
| 347 | 371 | * @param string $form_status 'published'|'preview' |
| @@ -447,9 +471,9 @@ | ||
| 447 | 471 | $resource_id = (int) $req['resource_id']; |
| 448 | 472 | $custom_booking_form = (string) $req['form_slug']; |
| 449 | 473 | |
| 450 | 474 | /** |
| 451 | - * $resolved = array( 'engine' : 'bfb_db'|'legacy'|'simple' | |
| 475 | + * $resolved = array( 'engine' : 'bfb_db'|'bfb_missing' | |
| 452 | 476 | * 'apply_after_load_filter' : bool |
| 453 | 477 | * 'bfb_loader_args' : array() |
| 454 | 478 | * 'fallback_chain' : array() |
| 455 | 479 | */ |
| @@ -466,33 +490,34 @@ | ||
| 466 | 490 | return $booking_form_html__arr; |
| 467 | 491 | } |
| 468 | 492 | } |
| 469 | 493 | |
| 470 | - // ----------------------------------------------------------------- | |
| 471 | - // Legacy engine (unchanged output). | |
| 472 | - // ----------------------------------------------------------------- | |
| 473 | - if ( ( ! empty( $legacy_instance ) ) | |
| 474 | - && ( false !== $legacy_instance->wpdev_bk_personal ) | |
| 475 | - // && ( 'On' != get_bk_option( 'booking_is_use_simple_booking_form' ) ) // Important! in paid versions, if edited in "Simple mode" the compiled form, still saved as "Advanced form" content, so we need to get it from there! | |
| 476 | - ) { | |
| 477 | - return array( | |
| 478 | - 'body_html' => $legacy_instance->wpdev_bk_personal->get_booking_form( $resource_id, $custom_booking_form, $custom_params ), | |
| 479 | - 'apply_after_load_filter' => false, | |
| 480 | - 'bfb_settings' => array(), | |
| 481 | - ); | |
| 482 | - } | |
| 494 | + return array( | |
| 495 | + 'body_html' => self::get_missing_bfb_form_html( $resolved ), | |
| 496 | + 'apply_after_load_filter' => false, | |
| 497 | + 'bfb_settings' => array(), | |
| 498 | + ); | |
| 499 | + } | |
| 500 | + | |
| 501 | + /** | |
| 502 | + * Render a controlled empty state when no BFB form row exists. | |
| 503 | + * | |
| 504 | + * @param array $resolved Resolver result. | |
| 505 | + * | |
| 506 | + * @return string | |
| 507 | + */ | |
| 508 | + private static function get_missing_bfb_form_html( $resolved ) { | |
| 509 | + | |
| 510 | + $reason = ( is_array( $resolved ) && ! empty( $resolved['reason'] ) ) ? (string) $resolved['reason'] : 'bfb_form_not_found'; | |
| 511 | + | |
| 512 | + if ( is_admin() || current_user_can( 'manage_options' ) ) { | |
| 513 | + return '<div class="wpbc_bfb_missing_form wpbc_alert_warning">' . esc_html__( 'Booking form configuration was not found. Please open the Booking Form Builder and save the form once.', 'booking' ) . ' <span class="wpbc_bfb_missing_reason">' . esc_html( $reason ) . '</span></div>'; | |
| 514 | + } | |
| 515 | + | |
| 516 | + return '<div class="wpbc_bfb_missing_form" style="display:none;"></div>'; | |
| 517 | + } | |
| 483 | 518 | |
| 484 | - // ----------------------------------------------------------------- | |
| 485 | - // Simple fallback. - ONLY for the Booking Calendar Free version ! | |
| 486 | - // ----------------------------------------------------------------- | |
| 487 | - return array( | |
| 488 | - 'body_html' => wpbc_simple_form__get_booking_form__as_html( $resource_id, $custom_booking_form, $custom_params ), | |
| 489 | - 'apply_after_load_filter' => true, | |
| 490 | - 'bfb_settings' => array(), | |
| 491 | - ); | |
| 492 | - } | |
| 493 | 519 | |
| 494 | - | |
| 495 | 520 | /** |
| 496 | 521 | * Get BFB booking form content array. Helper function. |
| 497 | 522 | * |
| 498 | 523 | * @param array $req - array. |
| @@ -571,9 +596,17 @@ | ||
| 571 | 596 | if ( '' === $bfb_form_html ) { |
| 572 | 597 | |
| 573 | 598 | $render_args = array_merge( $custom_params, array( 'booking_type' => (int) $resource_id ) ); |
| 574 | 599 | |
| 575 | - $bfb_source = wpbc_lang( $bfb_source ); | |
| 600 | + /* | |
| 601 | + * Do not pass the complete Builder form through wpbc_lang(). Builder | |
| 602 | + * labels and option values may contain legacy [lang=LOCALE] markers. | |
| 603 | + * Parsing one of those inline markers as a whole-form language block | |
| 604 | + * truncates everything before/after the matching field and can leave an | |
| 605 | + * incomplete form on the front end. BFB multilingual forms are separate | |
| 606 | + * custom forms and are selected by their form slug. | |
| 607 | + */ | |
| 608 | + $bfb_source = (string) $bfb_source; | |
| 576 | 609 | |
| 577 | 610 | // Replace custom params in the source (legacy behavior). |
| 578 | 611 | if ( ! empty( $custom_params ) ) { |
| 579 | 612 | foreach ( $custom_params as $custom_params_key => $custom_params_value ) { |
| @@ -705,15 +738,18 @@ | ||
| 705 | 738 | * @return string Wrapped HTML. |
| 706 | 739 | */ |
| 707 | 740 | public static function wrap( $form_html, $resource_id ) { |
| 708 | 741 | |
| 709 | - $resource_id = (int) $resource_id; | |
| 710 | - $wpbc_nonce = wp_nonce_field( 'CALCULATE_THE_COST', ( 'wpbc_nonceCALCULATE_THE_COST' . $resource_id ), true, false ); | |
| 742 | + $resource_id = (int) $resource_id; | |
| 743 | + $wpbc_nonce = wp_nonce_field( 'CALCULATE_THE_COST', ( 'wpbc_nonceCALCULATE_THE_COST' . $resource_id ), true, false ); | |
| 744 | + | |
| 745 | + $booking_form_is_using_bs_css = get_bk_option( 'booking_form_is_using_bs_css' ); | |
| 746 | + $booking_form_format_type = get_bk_option( 'booking_form_format_type' ); | |
| 747 | + $form_style_preset = function_exists( 'wpbc_bfb_settings__get_form_style_preset' ) | |
| 748 | + ? wpbc_bfb_settings__get_form_style_preset( wpbc_bfb_settings__get_current_form_style() ) | |
| 749 | + : array(); | |
| 750 | + $booking_form_theme = isset( $form_style_preset['theme_class'] ) ? sanitize_html_class( $form_style_preset['theme_class'] ) : ''; | |
| 711 | 751 | |
| 712 | - $booking_form_is_using_bs_css = get_bk_option( 'booking_form_is_using_bs_css' ); | |
| 713 | - $booking_form_format_type = get_bk_option( 'booking_form_format_type' ); | |
| 714 | - $booking_form_theme = get_bk_option( 'booking_form_theme' ); | |
| 715 | - | |
| 716 | 752 | $form_container_random_id = 'form_id' . ( time() * wp_rand( 0, 1000 ) ); |
| 717 | 753 | $form_container_css = 'wpbc_container wpbc_form wpbc_container_booking_form ' . ( ( 'On' === wpbc_is_this_demo() ) ? ' wpbc_demo_site ' : '' ) . |
| 718 | 754 | $booking_form_theme . ( ( 'On' === $booking_form_is_using_bs_css ) ? ' wpdevelop ' : '' ); |
| 719 | 755 | |
| @@ -842,72 +878,82 @@ | ||
| 842 | 878 | * @param array $css_vars Map: '--var-name' => 'value' |
| 843 | 879 | * |
| 844 | 880 | * @return string |
| 845 | 881 | */ |
| 846 | - public static function inject_css_vars_into_bfb_root( $html, $css_vars ) { | |
| 882 | + public static function inject_css_vars_into_bfb_root( $html, $css_vars ) { | |
| 883 | + | |
| 884 | + return self::inject_css_vars_into_first_tag_with_classes( $html, $css_vars, array( 'wpbc_bfb_form' ) ); | |
| 885 | + } | |
| 886 | + | |
| 887 | + /** | |
| 888 | + * Inject CSS variables into the FIRST outer booking form wrapper. | |
| 889 | + * | |
| 890 | + * @param string $html | |
| 891 | + * @param array $css_vars | |
| 892 | + * | |
| 893 | + * @return string | |
| 894 | + */ | |
| 895 | + public static function inject_css_vars_into_form_wrapper( $html, $css_vars ) { | |
| 896 | + | |
| 897 | + return self::inject_css_vars_into_first_tag_with_classes( $html, $css_vars, array( 'wpbc_container', 'wpbc_form' ) ); | |
| 898 | + } | |
| 899 | + | |
| 900 | + /** | |
| 901 | + * Add a class to the FIRST <div> with all required class tokens. | |
| 902 | + * | |
| 903 | + * @param string $html | |
| 904 | + * @param array $required_classes | |
| 905 | + * @param string $class_name | |
| 906 | + * | |
| 907 | + * @return string | |
| 908 | + */ | |
| 909 | + public static function add_class_to_first_tag_with_classes( $html, $required_classes, $class_name ) { | |
| 910 | + | |
| 911 | + $html = (string) $html; | |
| 912 | + $required_classes = is_array( $required_classes ) ? $required_classes : array(); | |
| 913 | + $class_name = sanitize_html_class( (string) $class_name ); | |
| 914 | + | |
| 915 | + if ( '' === $class_name || empty( $required_classes ) ) { | |
| 916 | + return $html; | |
| 917 | + } | |
| 918 | + | |
| 919 | + $pattern = self::get_first_div_with_classes_pattern( $required_classes ); | |
| 920 | + if ( '' === $pattern ) { | |
| 921 | + return $html; | |
| 922 | + } | |
| 923 | + | |
| 924 | + $done = false; | |
| 925 | + $result = preg_replace_callback( | |
| 926 | + $pattern, | |
| 927 | + function( $m ) use ( $required_classes, $class_name, &$done ) { | |
| 928 | + | |
| 929 | + $tag = $m[0]; | |
| 930 | + | |
| 931 | + if ( ! empty( $done ) || ! self::tag_has_required_classes( $tag, $required_classes ) ) { | |
| 932 | + return $tag; | |
| 933 | + } | |
| 934 | + | |
| 935 | + if ( ! preg_match( '/\bclass\s*=\s*(["\'])(.*?)\1/i', $tag, $cm ) ) { | |
| 936 | + return $tag; | |
| 937 | + } | |
| 938 | + | |
| 939 | + $quote = $cm[1]; | |
| 940 | + $classes = trim( preg_replace( '/\s+/', ' ', (string) $cm[2] ) ); | |
| 941 | + | |
| 942 | + if ( false === strpos( ' ' . $classes . ' ', ' ' . $class_name . ' ' ) ) { | |
| 943 | + $classes = trim( $classes . ' ' . $class_name ); | |
| 944 | + } | |
| 945 | + | |
| 946 | + $done = true; | |
| 947 | + | |
| 948 | + return preg_replace( '/\bclass\s*=\s*(["\'])(.*?)\1/i', 'class=' . $quote . esc_attr( $classes ) . $quote, $tag, 1 ); | |
| 949 | + }, | |
| 950 | + $html | |
| 951 | + ); | |
| 952 | + | |
| 953 | + return ( null === $result ) ? $html : $result; | |
| 954 | + } | |
| 847 | 955 | |
| 848 | - $html = (string) $html; | |
| 849 | - $css_vars = is_array( $css_vars ) ? $css_vars : array(); | |
| 850 | - | |
| 851 | - if ( empty( $css_vars ) ) { | |
| 852 | - return $html; | |
| 853 | - } | |
| 854 | - if ( false === strpos( $html, 'wpbc_bfb_form' ) ) { | |
| 855 | - return $html; | |
| 856 | - } | |
| 857 | - | |
| 858 | - $style_append = self::build_css_vars_style_fragment( $css_vars ); | |
| 859 | - if ( '' === $style_append ) { | |
| 860 | - return $html; | |
| 861 | - } | |
| 862 | - | |
| 863 | - // Match FIRST <div ... class="... wpbc_bfb_form ..."> tag. | |
| 864 | - $pattern = '/<div\b[^>]*\bclass\s*=\s*(["\'])(?:(?!\1).)*\bwpbc_bfb_form\b(?:(?!\1).)*\1[^>]*>/i'; | |
| 865 | - | |
| 866 | - $result = preg_replace_callback( | |
| 867 | - $pattern, | |
| 868 | - function( $m ) use ( $style_append ) { | |
| 869 | - | |
| 870 | - $tag = $m[0]; | |
| 871 | - | |
| 872 | - // If style already exists: append. | |
| 873 | - if ( preg_match( '/\bstyle\s*=\s*(["\'])(.*?)\1/i', $tag, $sm ) ) { | |
| 874 | - | |
| 875 | - $quote = $sm[1]; | |
| 876 | - $existing = (string) $sm[2]; | |
| 877 | - | |
| 878 | - // Avoid double-escaping if the tag already contains entities. | |
| 879 | - $existing = html_entity_decode( $existing, ENT_QUOTES, 'UTF-8' ); | |
| 880 | - | |
| 881 | - $merged = trim( $existing ); | |
| 882 | - if ( ( '' !== $merged ) && ( ';' !== substr( $merged, -1 ) ) ) { | |
| 883 | - $merged .= ';'; | |
| 884 | - } | |
| 885 | - $merged .= $style_append; | |
| 886 | - | |
| 887 | - $tag = preg_replace( | |
| 888 | - '/\bstyle\s*=\s*(["\'])(.*?)\1/i', | |
| 889 | - 'style=' . $quote . esc_attr( $merged ) . $quote, | |
| 890 | - $tag, | |
| 891 | - 1 | |
| 892 | - ); | |
| 893 | - | |
| 894 | - return $tag; | |
| 895 | - } | |
| 896 | - | |
| 897 | - // No style attr: add it. | |
| 898 | - $tag = rtrim( $tag, '>' ) . ' style="' . esc_attr( $style_append ) . '">'; | |
| 899 | - | |
| 900 | - return $tag; | |
| 901 | - }, | |
| 902 | - $html, | |
| 903 | - 1 | |
| 904 | - ); | |
| 905 | - | |
| 906 | - // preg_replace_callback can return null on regex error. | |
| 907 | - return ( null === $result ) ? $html : $result; | |
| 908 | - } | |
| 909 | - | |
| 910 | 956 | /** |
| 911 | 957 | * Build CSS vars fragment: "--a:1;--b:2;" |
| 912 | 958 | * |
| 913 | 959 | * @param array $css_vars |
| @@ -913,9 +959,9 @@ | ||
| 913 | 959 | * @param array $css_vars |
| 914 | 960 | * |
| 915 | 961 | * @return string |
| 916 | 962 | */ |
| 917 | - private static function build_css_vars_style_fragment( $css_vars ) { | |
| 963 | + private static function build_css_vars_style_fragment( $css_vars ) { | |
| 918 | 964 | |
| 919 | 965 | $out = ''; |
| 920 | 966 | |
| 921 | 967 | foreach ( $css_vars as $name => $value ) { |
| @@ -945,17 +991,17 @@ | ||
| 945 | 991 | if ( ! preg_match( '/^--[a-z0-9\-_]+$/i', $name ) ) { |
| 946 | 992 | return ''; |
| 947 | 993 | } |
| 948 | 994 | |
| 949 | - // Optional: enforce prefix to avoid abusing other vars (case-insensitive). | |
| 950 | - $lower = strtolower( $name ); | |
| 951 | - if ( 0 !== strpos( $lower, '--wpbc-' ) && 0 !== strpos( $lower, '--wpbc_bfb-' ) ) { | |
| 952 | - return ''; | |
| 953 | - } | |
| 995 | + // Optional: enforce prefix to avoid abusing other vars (case-insensitive). | |
| 996 | + $lower = strtolower( $name ); | |
| 997 | + if ( 0 !== strpos( $lower, '--wpbc-' ) && 0 !== strpos( $lower, '--wpbc_bfb-' ) && 0 !== strpos( $lower, '--wpbc_form-' ) ) { | |
| 998 | + return ''; | |
| 999 | + } | |
| 1000 | + | |
| 1001 | + return $name; | |
| 1002 | + } | |
| 954 | 1003 | |
| 955 | - return $name; | |
| 956 | - } | |
| 957 | - | |
| 958 | 1004 | private static function sanitize_css_var_value( $value ) { |
| 959 | 1005 | |
| 960 | 1006 | $value = is_scalar( $value ) ? trim( (string) $value ) : ''; |
| 961 | 1007 | if ( '' === $value ) { |
| @@ -974,7 +1020,113 @@ | ||
| 974 | 1020 | '', |
| 975 | 1021 | $value |
| 976 | 1022 | ); |
| 977 | 1023 | |
| 978 | - return trim( $value ); | |
| 979 | - } | |
| 980 | -} | |
| 1024 | + return trim( $value ); | |
| 1025 | + } | |
| 1026 | + | |
| 1027 | + private static function inject_css_vars_into_first_tag_with_classes( $html, $css_vars, $required_classes ) { | |
| 1028 | + | |
| 1029 | + $html = (string) $html; | |
| 1030 | + $css_vars = is_array( $css_vars ) ? $css_vars : array(); | |
| 1031 | + | |
| 1032 | + if ( empty( $css_vars ) ) { | |
| 1033 | + return $html; | |
| 1034 | + } | |
| 1035 | + | |
| 1036 | + $style_append = self::build_css_vars_style_fragment( $css_vars ); | |
| 1037 | + if ( '' === $style_append ) { | |
| 1038 | + return $html; | |
| 1039 | + } | |
| 1040 | + | |
| 1041 | + $pattern = self::get_first_div_with_classes_pattern( $required_classes ); | |
| 1042 | + if ( '' === $pattern ) { | |
| 1043 | + return $html; | |
| 1044 | + } | |
| 1045 | + | |
| 1046 | + $done = false; | |
| 1047 | + $result = preg_replace_callback( | |
| 1048 | + $pattern, | |
| 1049 | + function( $m ) use ( $required_classes, $style_append, &$done ) { | |
| 1050 | + | |
| 1051 | + $tag = $m[0]; | |
| 1052 | + | |
| 1053 | + if ( ! empty( $done ) || ! self::tag_has_required_classes( $tag, $required_classes ) ) { | |
| 1054 | + return $tag; | |
| 1055 | + } | |
| 1056 | + | |
| 1057 | + // If style already exists: append. | |
| 1058 | + if ( preg_match( '/\bstyle\s*=\s*(["\'])(.*?)\1/i', $tag, $sm ) ) { | |
| 1059 | + | |
| 1060 | + $quote = $sm[1]; | |
| 1061 | + $existing = (string) $sm[2]; | |
| 1062 | + | |
| 1063 | + // Avoid double-escaping if the tag already contains entities. | |
| 1064 | + $existing = html_entity_decode( $existing, ENT_QUOTES, 'UTF-8' ); | |
| 1065 | + | |
| 1066 | + $merged = trim( $existing ); | |
| 1067 | + if ( ( '' !== $merged ) && ( ';' !== substr( $merged, -1 ) ) ) { | |
| 1068 | + $merged .= ';'; | |
| 1069 | + } | |
| 1070 | + $merged .= $style_append; | |
| 1071 | + | |
| 1072 | + $done = true; | |
| 1073 | + | |
| 1074 | + return preg_replace( | |
| 1075 | + '/\bstyle\s*=\s*(["\'])(.*?)\1/i', | |
| 1076 | + 'style=' . $quote . esc_attr( $merged ) . $quote, | |
| 1077 | + $tag, | |
| 1078 | + 1 | |
| 1079 | + ); | |
| 1080 | + } | |
| 1081 | + | |
| 1082 | + // No style attr: add it. | |
| 1083 | + $done = true; | |
| 1084 | + return rtrim( $tag, '>' ) . ' style="' . esc_attr( $style_append ) . '">'; | |
| 1085 | + }, | |
| 1086 | + $html | |
| 1087 | + ); | |
| 1088 | + | |
| 1089 | + return ( null === $result ) ? $html : $result; | |
| 1090 | + } | |
| 1091 | + | |
| 1092 | + private static function get_first_div_with_classes_pattern( $required_classes ) { | |
| 1093 | + | |
| 1094 | + $required_classes = is_array( $required_classes ) ? $required_classes : array(); | |
| 1095 | + $has_class = false; | |
| 1096 | + | |
| 1097 | + foreach ( $required_classes as $class_name ) { | |
| 1098 | + $class_name = sanitize_html_class( (string) $class_name ); | |
| 1099 | + if ( '' === $class_name ) { | |
| 1100 | + continue; | |
| 1101 | + } | |
| 1102 | + $has_class = true; | |
| 1103 | + } | |
| 1104 | + | |
| 1105 | + if ( ! $has_class ) { | |
| 1106 | + return ''; | |
| 1107 | + } | |
| 1108 | + | |
| 1109 | + return '/<div\b[^>]*\bclass\s*=\s*(["\'])(.*?)\1[^>]*>/i'; | |
| 1110 | + } | |
| 1111 | + | |
| 1112 | + private static function tag_has_required_classes( $tag, $required_classes ) { | |
| 1113 | + | |
| 1114 | + if ( ! preg_match( '/\bclass\s*=\s*(["\'])(.*?)\1/i', (string) $tag, $cm ) ) { | |
| 1115 | + return false; | |
| 1116 | + } | |
| 1117 | + | |
| 1118 | + $classes = ' ' . preg_replace( '/\s+/', ' ', (string) $cm[2] ) . ' '; | |
| 1119 | + | |
| 1120 | + foreach ( (array) $required_classes as $class_name ) { | |
| 1121 | + $class_name = sanitize_html_class( (string) $class_name ); | |
| 1122 | + if ( '' === $class_name ) { | |
| 1123 | + continue; | |
| 1124 | + } | |
| 1125 | + if ( false === strpos( $classes, ' ' . $class_name . ' ' ) ) { | |
| 1126 | + return false; | |
| 1127 | + } | |
| 1128 | + } | |
| 1129 | + | |
| 1130 | + return true; | |
| 1131 | + } | |
| 1132 | +} | |