PluginProbe
Ultimate Post Kit – Elementor Post Grid, Post Carousel, Post Slider & Blog Layout Widgets / 4.5.6
Ultimate Post Kit – Elementor Post Grid, Post Carousel, Post Slider & Blog Layout Widgets v4.5.6
4.5.6 4.5.5 4.5.4 4.2.1 4.2.2 4.2.3 4.5.0 4.5.2 4.5.3 4.2.0 4.1.18 4.1.17 4.1.16 4.1.15 4.1.14 4.1.13 4.1.12 4.1.11 4.1.10 4.1.9 4.1.8 4.0.9 4.1.0 4.1.1 4.1.2 All 148 releases
← All changes | includes/helper.php +109 -3 4.5.0 → 4.5.6 View file →
@@ -819,11 +819,11 @@
819 819 'h3' => 'H3',
820 820 'h4' => 'H4',
821 821 'h5' => 'H5',
822 822 'h6' => 'H6',
823 - 'div' => 'div',
824 - 'span' => 'span',
825 - 'p' => 'p',
823 + 'div' => 'Div',
824 + 'span' => 'Span',
825 + 'p' => 'P',
826 826 ];
827 827
828 828 return $title_tags;
829 829 }
@@ -933,8 +933,11 @@
933 933 */
934 934
935 935 if ( _is_upk_pro_activated() ) {
936 936 function ultimate_post_kit_reading_time( $content, $avg_reading_speed, $hide_seconds = 'no', $hide_minutes = 'no' ) {
937 + $avg_reading_speed = is_scalar( $avg_reading_speed ) ? (int) $avg_reading_speed : 0;
938 + $avg_reading_speed = $avg_reading_speed > 0 ? $avg_reading_speed : 200;
939 +
937 940 $total_word = str_word_count( wp_strip_all_tags( $content ) );
938 941 $reading_minute = floor( $total_word / $avg_reading_speed );
939 942 $reading_seconds = floor( $total_word % $avg_reading_speed / ( $avg_reading_speed / 60 ) );
940 943
@@ -1002,4 +1005,107 @@
1002 1005 return false;
1003 1006 }
1004 1007 }
1005 1008
1009 +
1010 +/**
1011 + * Restrict a request-supplied post type to the ones this site already exposes to
1012 + * anonymous visitors.
1013 + *
1014 + * The load-more handlers are registered on wp_ajax_nopriv_* and rebuild their WP_Query
1015 + * from $_POST, so the post type they query is attacker-controlled. Post types that are
1016 + * public but flagged exclude_from_search (Elementor's elementor_library, for example)
1017 + * are deliberately hidden from anonymous visitors elsewhere, so they must not be
1018 + * reachable here either.
1019 + *
1020 + * @param string|array $post_type Requested post type(s).
1021 + * @param string $fallback Post type to fall back to when nothing is allowed.
1022 + * @return string|array Sanitized post type(s).
1023 + */
1024 +if ( ! function_exists( 'ultimate_post_kit_sanitize_public_post_type' ) ) {
1025 + function ultimate_post_kit_sanitize_public_post_type( $post_type, $fallback = 'post' ) {
1026 +
1027 + $is_allowed = static function ( $type ) {
1028 + $object = get_post_type_object( $type );
1029 +
1030 + return $object && is_post_type_viewable( $type ) && empty( $object->exclude_from_search );
1031 + };
1032 +
1033 + if ( is_array( $post_type ) ) {
1034 + $requested = array_filter( $post_type, 'is_scalar' );
1035 + $requested = array_values( array_filter( array_map( 'strval', $requested ), $is_allowed ) );
1036 +
1037 + return empty( $requested ) ? $fallback : $requested;
1038 + }
1039 +
1040 + if ( ! is_scalar( $post_type ) ) {
1041 + return $fallback;
1042 + }
1043 +
1044 + $post_type = (string) $post_type;
1045 +
1046 + return $is_allowed( $post_type ) ? $post_type : $fallback;
1047 + }
1048 +}
1049 +
1050 +/**
1051 + * Clamp a request-supplied excerpt word count.
1052 + *
1053 + * excerpt_length arrives from $_POST on the unauthenticated load-more handlers and is
1054 + * passed straight to wp_trim_words(), so an unbounded value returns effectively the
1055 + * whole post_content instead of a teaser.
1056 + *
1057 + * @param mixed $length Requested word count.
1058 + * @param int $default Value to use when the request supplies nothing usable.
1059 + * @return int Clamped word count.
1060 + */
1061 +if ( ! function_exists( 'ultimate_post_kit_clamp_excerpt_length' ) ) {
1062 + function ultimate_post_kit_clamp_excerpt_length( $length, $default = 20 ) {
1063 +
1064 + $length = is_scalar( $length ) ? (int) $length : 0;
1065 +
1066 + if ( $length < 1 ) {
1067 + $length = (int) $default;
1068 + }
1069 +
1070 + return max( 1, min( 200, $length ) );
1071 + }
1072 +}
1073 +
1074 +/**
1075 + * Make a request-supplied Elementor icon array safe to render.
1076 + *
1077 + * The load-more handlers run on wp_ajax_nopriv_* and rebuild their settings from $_POST.
1078 + * map_deep() preserves nested arrays, so an icon array reaches
1079 + * Elementor\Icons_Manager::render_icon() exactly as the caller shaped it. The 'svg'
1080 + * library branch resolves to Svg::get_inline_svg( $value['id'] ), which reads an
1081 + * attachment by id with no capability or post-status check, so an icon coming from a
1082 + * request must never be allowed to select it.
1083 + *
1084 + * @param mixed $icon Icon array as supplied by the request.
1085 + * @return array|false Safe icon array, or false when nothing renderable remains.
1086 + */
1087 +if ( ! function_exists( 'ultimate_post_kit_sanitize_request_icon' ) ) {
1088 + function ultimate_post_kit_sanitize_request_icon( $icon ) {
1089 +
1090 + if ( ! is_array( $icon ) || empty( $icon['library'] ) || ! is_scalar( $icon['library'] ) ) {
1091 + return false;
1092 + }
1093 +
1094 + $library = (string) $icon['library'];
1095 +
1096 + // Uploaded-SVG icons are addressed by attachment id; never resolve one from a request.
1097 + if ( 'svg' === $library ) {
1098 + return false;
1099 + }
1100 +
1101 + // Font icons are rendered as a CSS class, so the value must stay a scalar.
1102 + if ( ! isset( $icon['value'] ) || ! is_scalar( $icon['value'] ) ) {
1103 + return false;
1104 + }
1105 +
1106 + return [
1107 + 'library' => $library,
1108 + 'value' => (string) $icon['value'],
1109 + ];
1110 + }
1111 +}