/
githubmirror
/
gutenberg
Обзор
Документация
Войти
/
githubmirror
/
gutenberg
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
trunk
lib/compat/wordpress-7.0/script-modules.php
229 строк
7 KB
Ramon
Script Modules: Guard setAccessible() calls behind PHP < 8.1 check (#78137)
11 май 2026, 05:18
Не верифицирован
11 май 2026, 05:18
7145bd0
Код
Авторство
О чём код?
<?php /** * Script Modules API: Polyfill for script module translations. * * Provides translation support for script modules on WordPress versions * that do not yet include this functionality in Core. * * @package gutenberg * @since X.X.X */ /** * Gets the raw source URL for a registered script module. * * Uses WP_Script_Modules::get_registered() if available (WP 7.0+), * otherwise falls back to reflection to access the private registered array. * * @since X.X.X * * @param string $id The script module identifier. * @return string|null The script module source URL, or null if not registered. */ function gutenberg_get_script_module_src( string $id ): ?string { $script_modules = wp_script_modules(); if ( method_exists( $script_modules, 'get_registered' ) ) { $module = $script_modules->get_registered( $id ); return null === $module ? null : ( $module['src'] ?? null ); } // Fallback for WP versions without get_registered(). $reflection = new ReflectionClass( $script_modules ); $prop = $reflection->getProperty( 'registered' ); if ( PHP_VERSION_ID < 80100 ) { $prop->setAccessible( true ); } $registered = $prop->getValue( $script_modules ); return $registered[ $id ]['src'] ?? null; } /** * Prints translations for all enqueued script modules. * * Auto-detects the text domain for each enqueued module from its source URL. * * @since X.X.X */ function gutenberg_print_script_module_translations() { $script_modules = wp_script_modules(); $queue = $script_modules->get_queue(); if ( empty( $queue ) ) { return; } // Collect enqueued modules and their static/dynamic dependencies. $module_ids = array(); $reflection = new ReflectionClass( $script_modules ); if ( $reflection->hasMethod( 'get_sorted_dependencies' ) ) { $method = $reflection->getMethod( 'get_sorted_dependencies' ); if ( PHP_VERSION_ID < 80100 ) { $method->setAccessible( true ); } $module_ids = $method->invoke( $script_modules, $queue ); } else { $module_ids = $queue; } $set_locale_data_js_function = <<<'JS' ( domain, translations ) => { const localeData = translations.locale_data[ domain ] || translations.locale_data.messages; localeData[""].domain = domain; wp.i18n.setLocaleData( localeData, domain ); } JS; foreach ( $module_ids as $id ) { $json_translations = load_script_module_textdomain( $id ); if ( ! $json_translations ) { continue; } $output = sprintf( '( %s )( %s, %s );', $set_locale_data_js_function, wp_json_encode( 'default' ), $json_translations ); $source_url = rawurlencode( "wp-script-module-translation-data-{$id}" ); $output .= "\n//# sourceURL={$source_url}"; // Ensure wp-i18n is printed; the inline script below relies on wp.i18n.setLocaleData(). if ( ! wp_script_is( 'wp-i18n', 'done' ) ) { wp_scripts()->do_items( array( 'wp-i18n' ) ); } wp_print_inline_script_tag( $output, array( 'id' => "wp-script-module-translation-data-{$id}" ) ); } } // Print translations after classic scripts are loaded (priority 10) but before modules execute. add_action( 'wp_footer', 'gutenberg_print_script_module_translations', 21 ); add_action( 'admin_print_footer_scripts', 'gutenberg_print_script_module_translations', 11 ); if ( ! function_exists( 'load_script_module_textdomain' ) ) { /** * Loads the translation data for a given script module ID and text domain. * * Works like load_script_textdomain() but for script modules registered * via wp_register_script_module(). * * @since X.X.X * * @param string $id The script module identifier. * @param string $domain Optional. Text domain. Default 'default'. * @param string $path Optional. The full file path to the directory containing translation files. * @return string|false The JSON-encoded translated strings for the given script module and text domain. * False if there are none. */ function load_script_module_textdomain( $id, $domain = 'default', $path = '' ) { global $wp_textdomain_registry; $src = gutenberg_get_script_module_src( $id ); if ( null === $src ) { return false; } $locale = determine_locale(); if ( ! $path ) { $path = $wp_textdomain_registry->get( $domain, $locale ); } $path = untrailingslashit( $path ); $file_base = 'default' === $domain ? $locale : $domain . '-' . $locale; $handle_filename = $file_base . '-' . $id . '.json'; if ( $path ) { $translations = load_script_translations( $path . '/' . $handle_filename, $id, $domain ); if ( $translations ) { return $translations; } } if ( ! preg_match( '|^(https?:)?//|', $src ) ) { $src = site_url( $src ); } $relative = false; $languages_path = WP_LANG_DIR; $src_url = wp_parse_url( $src ); $content_url = wp_parse_url( content_url() ); $plugins_url = wp_parse_url( plugins_url() ); $site_url = wp_parse_url( site_url() ); $theme_root = get_theme_root(); if ( ( ! isset( $content_url['path'] ) || str_starts_with( $src_url['path'], $content_url['path'] ) ) && ( ! isset( $src_url['host'] ) || ! isset( $content_url['host'] ) || $src_url['host'] === $content_url['host'] ) ) { if ( isset( $content_url['path'] ) ) { $relative = substr( $src_url['path'], strlen( $content_url['path'] ) ); } else { $relative = $src_url['path']; } $relative = trim( $relative, '/' ); $relative = explode( '/', $relative ); $theme_dir = array_slice( explode( '/', $theme_root ), -1 ); $dirname = $theme_dir[0] === $relative[0] ? 'themes' : 'plugins'; $languages_path = WP_LANG_DIR . '/' . $dirname; $relative = array_slice( $relative, 2 ); $relative = implode( '/', $relative ); } elseif ( ( ! isset( $plugins_url['path'] ) || str_starts_with( $src_url['path'], $plugins_url['path'] ) ) && ( ! isset( $src_url['host'] ) || ! isset( $plugins_url['host'] ) || $src_url['host'] === $plugins_url['host'] ) ) { if ( isset( $plugins_url['path'] ) ) { $relative = substr( $src_url['path'], strlen( $plugins_url['path'] ) ); } else { $relative = $src_url['path']; } $relative = trim( $relative, '/' ); $relative = explode( '/', $relative ); $languages_path = WP_LANG_DIR . '/plugins'; $relative = array_slice( $relative, 1 ); $relative = implode( '/', $relative ); } elseif ( ! isset( $src_url['host'] ) || ! isset( $site_url['host'] ) || $src_url['host'] === $site_url['host'] ) { if ( ! isset( $site_url['path'] ) ) { $relative = trim( $src_url['path'], '/' ); } elseif ( str_starts_with( $src_url['path'], trailingslashit( $site_url['path'] ) ) ) { $relative = substr( $src_url['path'], strlen( $site_url['path'] ) ); $relative = trim( $relative, '/' ); } } /** This filter is documented in wp-includes/l10n.php */ $relative = apply_filters( 'load_script_textdomain_relative_path', $relative, $src, true ); if ( false === $relative ) { return load_script_translations( false, $id, $domain ); } if ( str_ends_with( $relative, '.min.js' ) ) { $relative = substr( $relative, 0, -7 ) . '.js'; } $md5_filename = $file_base . '-' . md5( $relative ) . '.json'; if ( $path ) { $translations = load_script_translations( $path . '/' . $md5_filename, $id, $domain ); if ( $translations ) { return $translations; } } $translations = load_script_translations( $languages_path . '/' . $md5_filename, $id, $domain ); if ( $translations ) { return $translations; } return load_script_translations( false, $id, $domain ); } }