From 24e550f589eca5cd4c56136ef2631e35f3a87f40 Mon Sep 17 00:00:00 2001 From: Peter Wilson <519727+peterwilsoncc@users.noreply.github.com> Date: Tue, 2 Apr 2024 16:32:48 +1100 Subject: [PATCH] Backport r57868 from WordPress-Develop. (#60141) Prevent font folder naive filtering causing infinite loops. This modifies the font directory API to more closely reflect the upload directory API to help account for naive filtering when uploading fonts. This moves the protection of infinite loops to the new function `_wp_filter_font_directory()` to allow developers extending and maintaining the font library to apply the filter without the need for a closure. These changes also ensure both the `upload_dir` and `font_dir` filter are applied consistently when both creating and deleting fonts faces. Prior to this commit the `upload_dir` filter was only fired when creating fonts faces via the REST API. Applying the font directory filter to the `upload_dir` filter is now done by adding the `_wp_filter_font_directory` function rather than `wp_get_font_dir()`. Developers who have previously modified the font upload directory using the `font_dir` filter will NOT need to upload their code. Co-authored-by: Grant Kinney --- .../class-wp-rest-font-faces-controller.php | 19 +--- lib/compat/wordpress-6.5/fonts/fonts.php | 88 +++++++++++++++++-- 2 files changed, 84 insertions(+), 23 deletions(-) diff --git a/lib/compat/wordpress-6.5/fonts/class-wp-rest-font-faces-controller.php b/lib/compat/wordpress-6.5/fonts/class-wp-rest-font-faces-controller.php index b1ab37cdef4ee..f8e7c56c52d40 100644 --- a/lib/compat/wordpress-6.5/fonts/class-wp-rest-font-faces-controller.php +++ b/lib/compat/wordpress-6.5/fonts/class-wp-rest-font-faces-controller.php @@ -858,21 +858,8 @@ protected function sanitize_src( $value ) { */ protected function handle_font_file_upload( $file ) { add_filter( 'upload_mimes', array( 'WP_Font_Utils', 'get_allowed_font_mime_types' ) ); - - /* - * Set the upload directory to the fonts directory. - * - * wp_get_font_dir() contains the 'font_dir' hook, whose callbacks are - * likely to call wp_get_upload_dir(). - * - * To avoid an infinite loop, don't hook wp_get_font_dir() to 'upload_dir'. - * Instead, just pass its return value to the 'upload_dir' callback. - */ - $font_dir = wp_get_font_dir(); - $set_upload_dir = function () use ( $font_dir ) { - return $font_dir; - }; - add_filter( 'upload_dir', $set_upload_dir ); + // Filter the upload directory to return the fonts directory. + add_filter( 'upload_dir', '_wp_filter_font_directory' ); $overrides = array( 'upload_error_handler' => array( $this, 'handle_font_file_upload_error' ), @@ -888,7 +875,7 @@ protected function handle_font_file_upload( $file ) { } $uploaded_file = wp_handle_upload( $file, $overrides ); - remove_filter( 'upload_dir', $set_upload_dir ); + remove_filter( 'upload_dir', '_wp_filter_font_directory' ); remove_filter( 'upload_mimes', array( 'WP_Font_Utils', 'get_allowed_font_mime_types' ) ); return $uploaded_file; diff --git a/lib/compat/wordpress-6.5/fonts/fonts.php b/lib/compat/wordpress-6.5/fonts/fonts.php index 0a12d420bc51f..0f7ef7809abbe 100644 --- a/lib/compat/wordpress-6.5/fonts/fonts.php +++ b/lib/compat/wordpress-6.5/fonts/fonts.php @@ -198,15 +198,36 @@ function gutenberg_register_font_collections() { } add_action( 'init', 'gutenberg_register_font_collections', 11 ); -// @core-merge: This code should probably go into Core's src/wp-includes/functions.php. +// @core-merge: This code should probably go into Core's src/wp-includes/fonts.php. if ( ! function_exists( 'wp_get_font_dir' ) ) { + /** + * Retrieves font uploads directory information. + * + * Same as wp_font_dir() but "light weight" as it doesn't attempt to create the font uploads directory. + * Intended for use in themes, when only 'basedir' and 'baseurl' are needed, generally in all cases + * when not uploading files. + * + * @since 6.5.0 + * + * @see wp_font_dir() + * + * @return array See wp_font_dir() for description. + */ + function wp_get_font_dir() { + return wp_font_dir( false ); + } +} + +// @core-merge: This code should probably go into Core's src/wp-includes/fonts.php. +if ( ! function_exists( 'wp_font_dir' ) ) { /** * Returns an array containing the current fonts upload directory's path and URL. * * @since 6.5.0 * - * @return array $defaults { - * Array of information about the upload directory. + * @param bool $create_dir Optional. Whether to check and create the font uploads directory. Default true. + * @return array { + * Array of information about the font upload directory. * * @type string $path Base directory and subdirectory or full path to the fonts upload directory. * @type string $url Base URL and subdirectory or absolute URL to the fonts upload directory. @@ -216,13 +237,57 @@ function gutenberg_register_font_collections() { * @type string|false $error False or error message. * } */ - function wp_get_font_dir() { + function wp_font_dir( $create_dir = true ) { + /* + * Allow extenders to manipulate the font directory consistently. + * + * Ensures the upload_dir filter is fired both when calling this function + * directly and when the upload directory is filtered in the Font Face + * REST API endpoint. + */ + add_filter( 'upload_dir', '_wp_filter_font_directory' ); + $font_dir = wp_upload_dir( null, $create_dir, false ); + remove_filter( 'upload_dir', '_wp_filter_font_directory' ); + return $font_dir; + } +} + +// @core-merge: This code should probably go into Core's src/wp-includes/fonts.php. +if ( ! function_exists( '_wp_filter_font_directory' ) ) { + /** + * Returns the font directory for use by the font library. + * + * This function is a callback for the {@see 'upload_dir'} filter. It is not + * intended to be called directly. Use wp_get_font_dir() instead. + * + * The function can be used when extending the font library to modify the upload + * destination for font files via the upload_dir filter. The recommended way to + * do this is: + * + * ```php + * add_filter( 'upload_dir', '_wp_filter_font_directory' ); + * // Your code to upload or sideload a font file. + * remove_filter( 'upload_dir', '_wp_filter_font_directory' ); + * ``` + * + * @since 6.5.0 + * @access private + * + * @param string $font_dir The font directory. + * @return string The modified font directory. + */ + function _wp_filter_font_directory( $font_dir ) { + if ( doing_filter( 'font_dir' ) ) { + // Avoid an infinite loop. + return $font_dir; + } + $site_path = ''; if ( is_multisite() && ! ( is_main_network() && is_main_site() ) ) { $site_path = '/sites/' . get_current_blog_id(); } - $defaults = array( + $font_dir = array( 'path' => path_join( WP_CONTENT_DIR, 'fonts' ) . $site_path, 'url' => untrailingslashit( content_url( 'fonts' ) ) . $site_path, 'subdir' => '', @@ -238,9 +303,18 @@ function wp_get_font_dir() { * * @since 6.5.0 * - * @param array $defaults The original fonts directory data. + * @param array $font_dir { + * Array of information about the font upload directory. + * + * @type string $path Base directory and subdirectory or full path to the fonts upload directory. + * @type string $url Base URL and subdirectory or absolute URL to the fonts upload directory. + * @type string $subdir Subdirectory + * @type string $basedir Path without subdir. + * @type string $baseurl URL path without subdir. + * @type string|false $error False or error message. + * } */ - return apply_filters( 'font_dir', $defaults ); + return apply_filters( 'font_dir', $font_dir ); } }