PluginProbe
Post Grid Gutenberg Blocks – PostX / 5.1.0
Post Grid Gutenberg Blocks – PostX v5.1.0
5.1.1 5.1.0 5.0.41 5.0.39 5.0.38 5.0.37 5.0.36 5.0.35 5.0.34 5.0.33 5.0.32 5.0.31 5.0.30 5.0.29 5.0.28 5.0.27 5.0.26 5.0.25 5.0.23 5.0.24 5.0.22 5.0.21 5.0.20 5.0.19 5.0.18 All 240 releases
← All changes | addons/custom_font/Custom_Font.php +94 -16 5.0.21 → 5.1.0 View file →
@@ -11,8 +11,10 @@
11 11 add_filter( 'manage_ultp_custom_font_posts_columns', array( $this, 'templates_table_head' ) );
12 12 add_action( 'manage_ultp_custom_font_posts_custom_column', array( $this, 'templates_table_content' ), 10, 2 );
13 13 add_filter( 'upload_mimes', array( $this, 'add_file_types_to_uploads' ) );
14 14 add_filter( 'wp_check_filetype_and_ext', array( $this, 'font_correct_filetypes' ), 10, 5 );
15 + add_filter( 'wp_handle_upload_prefilter', array( $this, 'sanitize_svg_upload' ) );
16 + add_filter( 'wp_handle_sideload_prefilter', array( $this, 'sanitize_svg_upload' ) );
15 17 add_filter( 'enter_title_here', array( $this, 'update_custom_font_title' ), 10, 2 );
16 18 }
17 19
18 20 public function update_custom_font_title( $title, $post ) {
@@ -42,11 +44,14 @@
42 44 $new_filetypes = array();
43 45 $new_filetypes['woff'] = 'font/woff';
44 46 $new_filetypes['woff2'] = 'font/woff2';
45 47 $new_filetypes['ttf'] = 'font/ttf';
46 - $new_filetypes['svg'] = 'image/svg+xml';
47 48 $new_filetypes['eot'] = 'font/ttf';
48 - $file_types = array_merge( $file_types, $new_filetypes );
49 + // SVG only for a custom font, where every upload is sanitized by sanitize_svg_upload().
50 + if ( $this->is_custom_font_upload() ) {
51 + $new_filetypes['svg'] = 'image/svg+xml';
52 + }
53 + $file_types = array_merge( $file_types, $new_filetypes );
49 54 return $file_types;
50 55 } else {
51 56 return $file_types;
52 57 }
@@ -51,9 +56,82 @@
51 56 return $file_types;
52 57 }
53 58 }
54 59
60 + /**
61 + * Whether the current request uploads to, or edits, a custom font the user may edit.
62 + *
63 + * Uploads from the font screen's media modal send the font as `post_id`; async-upload.php
64 + * checks its own nonce and refuses a `post_id` the user cannot edit. The screen itself is
65 + * recognised by the global post.
66 + *
67 + * @return bool
68 + */
69 + private function is_custom_font_upload() {
70 + if ( ! current_user_can( 'manage_options' ) ) {
71 + return false;
72 + }
73 + $post_id = isset( $_REQUEST['post_id'] ) ? absint( $_REQUEST['post_id'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read only to choose the context; async-upload.php verifies the media-form nonce.
74 + if ( ! $post_id ) {
75 + $post_id = (int) get_the_ID();
76 + }
77 + return $post_id > 0 && 'ultp_custom_font' === get_post_type( $post_id ) && current_user_can( 'edit_post', $post_id );
78 + }
55 79
80 +
81 + /**
82 + * Clean an SVG uploaded to a custom font.
83 + *
84 + * Only runs for custom font uploads, the one place this add-on allows SVG. The file keeps
85 + * only its font markup; an SVG that is not a font is refused. SVG uploads anywhere else
86 + * are not touched here: WordPress refuses them unless another plugin allows SVG.
87 + *
88 + * @param array $file Upload data from `$_FILES`.
89 + * @return array
90 + */
91 + public function sanitize_svg_upload( $file ) {
92 + if ( empty( $file['name'] ) || empty( $file['tmp_name'] ) || ! empty( $file['error'] ) ) {
93 + return $file;
94 + }
95 + if ( 'svg' !== strtolower( pathinfo( $file['name'], PATHINFO_EXTENSION ) ) ) {
96 + return $file;
97 + }
98 + if ( ! $this->is_custom_font_upload() ) {
99 + return $file;
100 + }
101 +
102 + require_once __DIR__ . '/Svg_Font_Sanitizer.php';
103 + $sanitized = Svg_Font_Sanitizer::sanitize_file( $file['tmp_name'] );
104 + if ( is_wp_error( $sanitized ) ) {
105 + $file['error'] = $sanitized->get_error_message();
106 + }
107 + return $file;
108 + }
109 +
110 + /**
111 + * Font weight as stored and printed: 100-900 in steps of 100, normal or bold.
112 + *
113 + * @param string $weight Raw weight.
114 + * @return string
115 + */
116 + public static function sanitize_font_weight( $weight ) {
117 + $weight = strtolower( trim( (string) $weight ) );
118 + if ( in_array( $weight, array( 'normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900' ), true ) ) {
119 + return $weight;
120 + }
121 + return 'normal';
122 + }
123 +
124 + /**
125 + * Font family name safe to print inside a CSS string or a style attribute.
126 + *
127 + * @param string $font_name Post title of the font.
128 + * @return string
129 + */
130 + public static function sanitize_font_family( $font_name ) {
131 + return str_replace( array( '"', '\\', ';', '{', '}', '<', '>' ), '', (string) $font_name );
132 + }
133 +
56 134 // Template Heading Add
57 135 public function templates_table_head( $defaults ) {
58 136 $type_array = array(
59 137 'preview' => '<span class="ultp-custom-font-preview-th">' . __( 'Preview', 'ultimate-post' ) . '</span>',
@@ -88,10 +166,10 @@
88 166 if ( $settings['eot'] ) {
89 167 array_push( $font_src, 'url(' . esc_url( $settings['eot'] ) . ') format("eot")' );
90 168 }
91 169 $font_face = '@font-face {
92 - font-family: "' . $font_name . '";
93 - font-weight: ' . $settings['weight'] . ';
170 + font-family: "' . self::sanitize_font_family( $font_name ) . '";
171 + font-weight: ' . self::sanitize_font_weight( isset( $settings['weight'] ) ? $settings['weight'] : '' ) . ';
94 172 src: ' . implode( ', ', $font_src ) . ';
95 173 }';
96 174
97 175 return $font_face;
@@ -116,9 +194,9 @@
116 194 if ( $value['eot'] ) {
117 195 $eot = true; }
118 196 }
119 197 $font_face = $this->get_font_face( $settings[0], get_the_title( $post_id ) );
120 - echo '<style type="text/css">' . $font_face . '</style>'; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
198 + echo '<style type="text/css">' . $font_face . '</style>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CSS from get_font_face(): URLs pass esc_url(), family and weight pass sanitize_font_family()/sanitize_font_weight().
121 199
122 200 switch ( $column_id ) {
123 201 case 0:
124 202 echo '<span class="ultp-custom-font-preview" style="font-family: ' . esc_attr( get_the_title( $post_id ) ) . '">' . esc_html__( 'The quick brown fox jumps over the lazy dog.', 'ultimate-post' ) . '</span>';
@@ -160,9 +238,9 @@
160 238 ?>
161 239 <div class="ultp-custom-font-container ultp-custom-font<?php echo empty( $arr ) ? '-copy' : ''; ?>">
162 240 <div class="ultp-custom-font-heading">
163 241 <div>
164 - <label class="font-label"><?php echo esc_html__( 'Weight: ', 'ultimate-post' ); ?> <span class="ultp-custom-font-weight"> <?php echo esc_html__( isset( $arr['weight'] ) ? $arr['weight'] : '', 'ultimate-post' ); ?> </span></label>
242 + <label class="font-label"><?php echo esc_html__( 'Weight: ', 'ultimate-post' ); ?> <span class="ultp-custom-font-weight"> <?php echo esc_html( isset( $arr['weight'] ) ? $arr['weight'] : '' ); ?> </span></label>
165 243 <select name="weight[]">
166 244 <?php $weight = isset( $arr['weight'] ) ? $arr['weight'] : ''; ?>
167 245 <option <?php selected( $weight, 'normal' ); ?> value="normal"><?php echo esc_html__( 'Normal', 'ultimate-post' ); ?></option>
168 246 <option <?php selected( $weight, '100' ); ?> value="100"><?php echo esc_html__( '100', 'ultimate-post' ); ?></option>
@@ -176,16 +254,16 @@
176 254 <option <?php selected( $weight, '900' ); ?> value="900"><?php echo esc_html__( '900', 'ultimate-post' ); ?></option>
177 255 </select>
178 256 </div>
179 257 <?php
180 - $styles = '';
258 + $preview_style = '';
181 259 if ( ! empty( $arr ) ) {
182 260 $font_face = $this->get_font_face( $arr, $font_name );
183 - echo '<style type="text/css">' . $font_face . '</style>'; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
184 - $styles = 'style="font-family: ' . $font_name . '; font-weight: ' . $arr['weight'] . ' "';
261 + echo '<style type="text/css">' . $font_face . '</style>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CSS from get_font_face(): URLs pass esc_url(), family and weight pass sanitize_font_family()/sanitize_font_weight().
262 + $preview_style = 'font-family: "' . self::sanitize_font_family( $font_name ) . '"; font-weight: ' . self::sanitize_font_weight( isset( $arr['weight'] ) ? $arr['weight'] : '' );
185 263 }
186 264 ?>
187 - <span <?php echo $styles; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> class="ultp-custom-font-preview"><?php echo esc_html__( 'The quick brown fox jumps over the lazy dog', 'ultimate-post' ); ?></span>
265 + <span <?php echo '' !== $preview_style ? 'style="' . esc_attr( $preview_style ) . '"' : ''; ?> class="ultp-custom-font-preview"><?php echo esc_html__( 'The quick brown fox jumps over the lazy dog', 'ultimate-post' ); ?></span>
188 266 <div class="ultp-custom-font-actions">
189 267 <span class="ultp-custom-font-edit"><span class="dashicons dashicons-edit"></span><?php echo esc_html__( 'Edit', 'ultimate-post' ); ?></span>
190 268 <span class="ultp-custom-font-close"><span class="dashicons dashicons-no-alt"></span><?php echo esc_html__( 'Close', 'ultimate-post' ); ?></span>
191 269 <span class="ultp-custom-font-delete"><span class="dashicons dashicons-trash"></span><?php echo esc_html__( 'Delete', 'ultimate-post' ); ?></span>
@@ -253,14 +331,14 @@
253 331 ! empty( $_POST['ttf'][ $i ] ) ||
254 332 ! empty( $_POST['svg'][ $i ] ) ||
255 333 ! empty( $_POST['eot'][ $i ] ) ) ) {
256 334 $temp = array();
257 - $temp['weight'] = isset( $_POST['weight'][ $i ] ) ? sanitize_text_field( $_POST['weight'][ $i ] ) : '';
258 - $temp['woff'] = isset( $_POST['woff'][ $i ] ) ? sanitize_text_field( $_POST['woff'][ $i ] ) : '';
259 - $temp['woff2'] = isset( $_POST['woff2'][ $i ] ) ? sanitize_text_field( $_POST['woff2'][ $i ] ) : '';
260 - $temp['ttf'] = isset( $_POST['ttf'][ $i ] ) ? sanitize_text_field( $_POST['ttf'][ $i ] ) : '';
261 - $temp['svg'] = isset( $_POST['svg'][ $i ] ) ? sanitize_text_field( $_POST['svg'][ $i ] ) : '';
262 - $temp['eot'] = isset( $_POST['eot'][ $i ] ) ? sanitize_text_field( $_POST['eot'][ $i ] ) : '';
335 + $temp['weight'] = self::sanitize_font_weight( sanitize_text_field( $_POST['weight'][ $i ] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- update_post_meta() unslashes; unslashing here would strip backslashes twice.
336 + $temp['woff'] = isset( $_POST['woff'][ $i ] ) ? sanitize_text_field( $_POST['woff'][ $i ] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- update_post_meta() unslashes; unslashing here would strip backslashes twice.
337 + $temp['woff2'] = isset( $_POST['woff2'][ $i ] ) ? sanitize_text_field( $_POST['woff2'][ $i ] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- update_post_meta() unslashes; unslashing here would strip backslashes twice.
338 + $temp['ttf'] = isset( $_POST['ttf'][ $i ] ) ? sanitize_text_field( $_POST['ttf'][ $i ] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- update_post_meta() unslashes; unslashing here would strip backslashes twice.
339 + $temp['svg'] = isset( $_POST['svg'][ $i ] ) ? sanitize_text_field( $_POST['svg'][ $i ] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- update_post_meta() unslashes; unslashing here would strip backslashes twice.
340 + $temp['eot'] = isset( $_POST['eot'][ $i ] ) ? sanitize_text_field( $_POST['eot'][ $i ] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- update_post_meta() unslashes; unslashing here would strip backslashes twice.
263 341 $arr[] = $temp;
264 342 }
265 343 }
266 344 update_post_meta( $post_id, '__font_settings', $arr );