if (!empty($json_translations)) { $output = <<getPluginConstant(Constants::PLUGIN_CONST_ROOT_SLUG) . '-', '/', $file); } /** * Force the basename for the md5 of a loaded JSON translation file. * * @param string $src * @see https://github.com/wp-cli/i18n-command/issues/177#issuecomment-523759266 */ public function load_script_textdomain_relative_path($src) { return \basename($src); } /** * Get the cachebuster entry for a given file. If the $src begins with public/lib/ it * will use the inc/base/others/cachebuster-lib.php cachebuster instead of inc/base/others/cachebuster.php. * * @param string $src The src relative to public/ folder * @param boolean $isLib If true the cachebuster-lib.php cachebuster is used * @param string $default * @return string _VERSION or cachebuster timestamp */ public function getCachebusterVersion($src, $isLib = \false, $default = null) { $default = $default ?? $this->getPluginConstant(Constants::PLUGIN_CONST_VERSION); $path = $this->getPluginConstant(Constants::PLUGIN_CONST_INC) . '/base/others/'; $path_lib = $path . 'cachebuster-lib.php'; $path = $path . 'cachebuster.php'; if ($isLib) { // Library cachebuster if (\file_exists($path_lib)) { static $cachebuster_lib = null; if ($cachebuster_lib === null) { $cachebuster_lib = (include $path_lib); } // Parse module \preg_match('/^public\\/lib\\/([^\\/]+)/', $src, $matches); if (\is_array($matches) && isset($matches[1]) && \is_array($cachebuster_lib) && \array_key_exists($matches[1], $cachebuster_lib)) { // Valid cachebuster return $cachebuster_lib[$matches[1]]; } } } else { // Main cachebuster if (\file_exists($path)) { // Store cachebuster once static $cachebuster = null; if ($cachebuster === null) { $cachebuster = (include $path); } // Prepend src/ because the cachebuster task prefixes it $src = 'src/' . $src; if (\is_array($cachebuster) && \array_key_exists($src, $cachebuster)) { // Valid cachebuster return $cachebuster[$src]; } } } return $default; } /** * Make a localized array anonymous. Some plugins like WP Rocket tries to lazy load also localized scripts * and this should be avoided in some scenarios like Real Cookie Banners' banner script. * Use this instead of `wp_localize_script`. * * Settings: * * ``` * string[] makeBase64Encoded List of keys of the array object which should be converted to base64 at output time (e.g. to avoid ModSecurity issues) * boolean useCore Use `wp_localize_script` internally instead of custom localize script * string[] lazyParse A list of pathes of the array which should be lazy parsed. This could be useful to improve performance and parse as needed (e.g. huge arrays). * ``` * * @param string $handle Name of the script to attach data to. * @param string $object_name Name of the variable that will contain the data. * @param array $l10n Array of data to localize. * @param array $settings * @see https://docs.wp-rocket.me/article/1349-delay-javascript-execution#technical * @see https://developer.wordpress.org/reference/functions/wp_localize_script/ */ public function anonymous_localize_script($handle, $object_name, $l10n, $settings = []) { $settings = \wp_parse_args($settings, ['makeBase64Encoded' => [], 'useCore' => \false, 'lazyParse' => []]); if ($settings['useCore']) { return \wp_localize_script($handle, $object_name, $l10n); } $makeBase64Encoded = $settings['makeBase64Encoded']; $lazyParse = $settings['lazyParse']; // Mark the script tag with some identifier, so our helper script (added below) can read // the JSON content. See also about: https://stackoverflow.com/q/12090883/5506547 // Do not use a randomized string as it can lead to issues with cached web pages when the // inline scripts gets somehow into a combined file and the HTML is served not statically. $uuid = \wp_generate_uuid4(); $uuid = \md5(\sprintf('%s:%s:%s', $handle, $object_name, $this->getPluginConstant(Constants::PLUGIN_CONST_VERSION))); $base64Marker = 'base64-encoded:'; \add_filter('script_loader_tag', function ($tag, $scriptHandle) use($handle, $uuid, $l10n, $object_name, $makeBase64Encoded, $base64Marker, $lazyParse) { if ($scriptHandle === $handle) { if (\count($makeBase64Encoded) > 0) { \array_walk_recursive($l10n, function (&$val, $key) use($makeBase64Encoded, $base64Marker) { if (\in_array($key, $makeBase64Encoded, \true) && \is_string($val) && !empty($val)) { $val = \sprintf('%s%s', $base64Marker, \base64_encode($val)); } }); } $foundLazyParse = []; // Only work with pathes which got converted successfully foreach ($lazyParse as $arrayPath) { Utils::arrayModifyByKeyPath($l10n, $arrayPath, function ($value) use($arrayPath, &$foundLazyParse) { $foundLazyParse[] = $arrayPath; return \json_encode($value); }); } /* (() => { var receiver = %5$s; var createLazyParseProxy = (obj, key) => new Proxy(obj, { get: (target, property) => { let value = Reflect.get(target, property); if (property === key && typeof value === "string") { value = JSON.parse(value, receiver); Reflect.set(target, property, value); } return value; } }); var o = /* document.write * / JSON.parse(document.getElementById("a%1$s1-js-extra").innerHTML, receiver); %6$s window.%3$s = o; const randomId = Math.random().toString(36).substring(2); window[randomId] = n; })(); */ $tag = \sprintf(' ', $uuid, \wp_json_encode($l10n), $object_name, \join(' ', [ // TODO: shouldn't this be part of @devowl-wp/cache-invalidate? // Compatibility with most caching plugins which lazy load JavaScript 'data-skip-lazy-load="js-extra"', // Compatibility with WP Fastest Cache and "Eliminate render blocking script" // as WPFC is moving all scripts (even with `type="text/plain"`). 'data-skip-moving="true"', // Compatibility with LiteSpeed Cache and do not delay this inline script // See https://github.com/litespeedtech/lscache_wp/blob/6c95240003b89ef1d4ce190f5a96eba83528cd89/src/optimize.cls.php#L903 'data-no-defer', // Compatibility with NitroPack 'nitro-exclude', // Compatibility with WP Rocket as the filter `rocket_defer_inline_exclusions` does only check on `