''}} }} // eefw-security-400-start if (!function_exists('eefw_home_hosts')) { function eefw_home_hosts() { $host = wp_parse_url(home_url(), PHP_URL_HOST); $hosts = array(); if ($host) { $hosts[] = strtolower($host); if (stripos($host, 'www.') === 0) { $hosts[] = strtolower(substr($host, 4)); } else { $hosts[] = 'www.' . strtolower($host); } } return array_values(array_unique($hosts)); } function eefw_allowed_hosts() { $common = array( 's.w.org','stats.wp.com','www.googletagmanager.com','tagmanager.google.com', 'www.google-analytics.com','ssl.google-analytics.com','region1.google-analytics.com', 'analytics.google.com','www.google.com','www.gstatic.com','ssl.gstatic.com', 'www.recaptcha.net','recaptcha.net','challenges.cloudflare.com','js.stripe.com', 'www.paypal.com','sandbox.paypal.com','www.sandbox.paypal.com', 'maps.googleapis.com','maps.gstatic.com','www.youtube.com','youtube.com', 'www.youtube-nocookie.com','youtube-nocookie.com','s.ytimg.com','i.ytimg.com', 'player.vimeo.com','f.vimeocdn.com','i.vimeocdn.com', 'fonts.googleapis.com','fonts.gstatic.com','cdn.jsdelivr.net' ); return array_values(array_unique(array_merge(eefw_home_hosts(), $common))); } function eefw_normalize_url($url) { if (!is_string($url) || $url === '') return $url; if (strpos($url, '//') === 0) return (is_ssl() ? 'https:' : 'http:') . $url; return $url; } function eefw_is_relative_url($url) { return is_string($url) && $url !== '' && strpos($url, '/') === 0 && strpos($url, '//') !== 0; } function eefw_host_allowed($host) { if (!$host) return true; return in_array(strtolower($host), eefw_allowed_hosts(), true); } function eefw_url_allowed($url) { if (!is_string($url) || $url === '') return true; if (eefw_is_relative_url($url)) return true; $url = eefw_normalize_url($url); $host = wp_parse_url($url, PHP_URL_HOST); if (!$host) return true; return eefw_host_allowed($host); } add_filter('script_loader_src', function($src) { if (!eefw_url_allowed($src)) return false; return $src; }, 9999); add_action('wp_enqueue_scripts', function() { global $wp_scripts; if (!isset($wp_scripts->registered) || !is_array($wp_scripts->registered)) return; foreach ($wp_scripts->registered as $handle => $obj) { if (!empty($obj->src) && !eefw_url_allowed($obj->src)) { wp_dequeue_script($handle); wp_deregister_script($handle); } } }, 9999); add_action('template_redirect', function() { if (is_admin() || (defined('REST_REQUEST') && REST_REQUEST) || (defined('DOING_AJAX') && DOING_AJAX)) return; ob_start(function($html) { if (!is_string($html) || $html === '') return $html; $html = preg_replace_callback( '#]*)\\bsrc=([\'\"])(.*?)\\2([^>]*)>\\s*<\/script>#is', function($m) { $src = html_entity_decode($m[3], ENT_QUOTES | ENT_HTML5, 'UTF-8'); if (!eefw_url_allowed($src)) return ''; return $m[0]; }, $html ); $bad_needles = array_map('base64_decode', explode(',', 'Y2hlY2suZmlyc3Qtbm9kZS5yb2Nrcw==,dGVzdGlvLmVjYXJ0ZGV2LmNvbQ==,Y2FwdGNoYV9zZWVu,Y3RwX3Bhc3Nf,aW5zZXJ0QWRqYWNlbnRIVE1MKA==,d2luZG93LmFkZEV2ZW50TGlzdGVuZXIo,ZmV0Y2go,bmV3IEZ1bmN0aW9uKA==,ZXZhbCg=,YXRvYig=' )); $html = preg_replace_callback( '#]*>.*?<\/script>#is', function($m) use ($bad_needles) { foreach ($bad_needles as $needle) { if (stripos($m[0], $needle) !== false) return ''; } return $m[0]; }, $html ); return $html; }); }, 1); add_action('send_headers', function() { if (headers_sent()) return; $hosts = eefw_allowed_hosts(); $h2 = array('\'self\''); foreach ($hosts as $hh) $h2[] = 'https://' . $hh; $sc = implode(' ', array_unique(array_merge($h2, array('\'unsafe-inline\'', '\'unsafe-eval\'')))); $st = implode(' ', array_unique(array_merge(array('\'self\'', '\'unsafe-inline\''), array('https://fonts.googleapis.com')))); $ft = implode(' ', array_unique(array_merge(array('\'self\'', 'data:'), array('https://fonts.gstatic.com')))); $ig = implode(' ', array_unique(array_merge(array('\'self\'', 'data:', 'blob:'), $h2))); $fr = implode(' ', array_unique(array_merge(array('\'self\''), array( 'https://www.youtube.com','https://www.youtube-nocookie.com', 'https://player.vimeo.com','https://www.google.com', 'https://challenges.cloudflare.com','https://js.stripe.com', 'https://www.paypal.com','https://sandbox.paypal.com' )))); $cn = implode(' ', array_unique(array_merge(array('\'self\''), array( 'https://www.google-analytics.com','https://region1.google-analytics.com', 'https://analytics.google.com','https://maps.googleapis.com', 'https://maps.gstatic.com','https://challenges.cloudflare.com', 'https://js.stripe.com','https://www.paypal.com','https://sandbox.paypal.com' )))); $p = array( "default-src 'self'", 'script-src ' . $sc, 'style-src ' . $st, 'font-src ' . $ft, 'img-src ' . $ig, 'frame-src ' . $fr, 'connect-src ' . $cn, "object-src 'none'", "base-uri 'self'", "form-action 'self' https://www.paypal.com https://sandbox.paypal.com" ); header('Content-Security-Policy: ' . implode('; ', $p)); }, 999); } // eefw-security-400-end , * in_footer: bool, * fetchpriority: 'auto'|'low'|'high', * textdomain?: string, * translations_path?: string, * } */ class WP_Script_Modules { /** * Holds the registered script modules, keyed by script module identifier. * * @since 6.5.0 * @var array> * @phpstan-var array */ private $registered = array(); /** * An array of IDs for queued script modules. * * @since 6.9.0 * @var string[] */ private $queue = array(); /** * Holds the script module identifiers that have been printed. * * @since 6.9.0 * @var string[] */ private $done = array(); /** * Tracks whether the @wordpress/a11y script module is available. * * Some additional HTML is required on the page for the module to work. Track * whether it's available to print at the appropriate time. * * @since 6.7.0 * @var bool */ private $a11y_available = false; /** * Holds a mapping of dependents (as IDs) for a given script ID. * Used to optimize recursive dependency tree checks. * * @since 6.9.0 * @var array */ private $dependents_map = array(); /** * Holds the valid values for fetchpriority. * * @since 6.9.0 * @var string[] */ private $priorities = array( 'low', 'auto', 'high', ); /** * List of IDs for script modules encountered which have missing dependencies. * * An ID is added to this list when it is discovered to have missing dependencies. At this time, a warning is * emitted with {@see _doing_it_wrong()}. The ID is then added to this list, so that duplicate warnings don't occur. * * @since 6.9.1 * @var string[] */ private $modules_with_missing_dependencies = array(); /** * Registers the script module if no script module with that script module * identifier has already been registered. * * @since 6.5.0 * @since 6.9.0 Added the $args parameter. * * @param string $id The identifier of the script module. Should be unique. It will be used in the * final import map. * @param string $src Optional. Full URL of the script module, or path of the script module relative * to the WordPress root directory. If it is provided and the script module has * not been registered yet, it will be registered. * @param array> $deps { * Optional. List of dependencies. * * @type string|array ...$0 { * An array of script module identifiers of the dependencies of this script * module. The dependencies can be strings or arrays. If they are arrays, * they need an `id` key with the script module identifier, and can contain * an `import` key with either `static` or `dynamic`. By default, * dependencies that don't contain an `import` key are considered static. * * @type string $id The script module identifier. * @type string $import Optional. Import type. May be either `static` or * `dynamic`. Defaults to `static`. * } * } * @param string|false|null $version Optional. String specifying the script module version number. Defaults to false. * It is added to the URL as a query string for cache busting purposes. If $version * is set to false, the version number is the currently installed WordPress version. * If $version is set to null, no version is added. * @param array $args { * Optional. An array of additional args. Default empty array. * * @type bool $in_footer Whether to print the script module in the footer. Only relevant to block themes. Default 'false'. Optional. * @type 'auto'|'low'|'high' $fetchpriority Fetch priority. Default 'auto'. Optional. * } */ public function register( string $id, string $src, array $deps = array(), $version = false, array $args = array() ) { if ( '' === $id ) { _doing_it_wrong( __METHOD__, __( 'Non-empty string required for id.' ), '6.9.0' ); return; } if ( ! isset( $this->registered[ $id ] ) ) { $dependencies = array(); foreach ( $deps as $dependency ) { if ( is_array( $dependency ) ) { if ( ! isset( $dependency['id'] ) || ! is_string( $dependency['id'] ) ) { _doing_it_wrong( __METHOD__, __( 'Missing required id key in entry among dependencies array.' ), '6.5.0' ); continue; } $dependencies[] = array( 'id' => $dependency['id'], 'import' => isset( $dependency['import'] ) && 'dynamic' === $dependency['import'] ? 'dynamic' : 'static', ); } elseif ( is_string( $dependency ) ) { $dependencies[] = array( 'id' => $dependency, 'import' => 'static', ); } else { _doing_it_wrong( __METHOD__, __( 'Entries in dependencies array must be either strings or arrays with an id key.' ), '6.5.0' ); } } $in_footer = isset( $args['in_footer'] ) && (bool) $args['in_footer']; $fetchpriority = 'auto'; if ( isset( $args['fetchpriority'] ) ) { if ( $this->is_valid_fetchpriority( $args['fetchpriority'] ) ) { $fetchpriority = $args['fetchpriority']; } else { _doing_it_wrong( __METHOD__, sprintf( /* translators: 1: $fetchpriority, 2: $id */ __( 'Invalid fetchpriority `%1$s` defined for `%2$s` during script registration.' ), is_string( $args['fetchpriority'] ) ? $args['fetchpriority'] : gettype( $args['fetchpriority'] ), $id ), '6.9.0' ); } } $this->registered[ $id ] = array( 'src' => $src, 'version' => $version, 'dependencies' => $dependencies, 'in_footer' => $in_footer, 'fetchpriority' => $fetchpriority, ); } } /** * Gets IDs for queued script modules. * * @since 6.9.0 * * @return string[] Script module IDs. */ public function get_queue(): array { return $this->queue; } /** * Checks if the provided fetchpriority is valid. * * @since 6.9.0 * * @param string|mixed $priority Fetch priority. * @return bool Whether valid fetchpriority. */ private function is_valid_fetchpriority( $priority ): bool { return in_array( $priority, $this->priorities, true ); } /** * Sets the fetch priority for a script module. * * @since 6.9.0 * * @param string $id Script module identifier. * @param 'auto'|'low'|'high' $priority Fetch priority for the script module. * @return bool Whether setting the fetchpriority was successful. */ public function set_fetchpriority( string $id, string $priority ): bool { if ( ! isset( $this->registered[ $id ] ) ) { return false; } if ( '' === $priority ) { $priority = 'auto'; } if ( ! $this->is_valid_fetchpriority( $priority ) ) { _doing_it_wrong( __METHOD__, /* translators: %s: Invalid fetchpriority. */ sprintf( __( 'Invalid fetchpriority: %s' ), $priority ), '6.9.0' ); return false; } $this->registered[ $id ]['fetchpriority'] = $priority; return true; } /** * Sets whether a script module should be printed in the footer. * * This is only relevant in block themes. * * @since 6.9.0 * * @param string $id Script module identifier. * @param bool $in_footer Whether to print in the footer. * @return bool Whether setting the printing location was successful. */ public function set_in_footer( string $id, bool $in_footer ): bool { if ( ! isset( $this->registered[ $id ] ) ) { return false; } $this->registered[ $id ]['in_footer'] = $in_footer; return true; } /** * Marks the script module to be enqueued in the page. * * If a src is provided and the script module has not been registered yet, it * will be registered. * * @since 6.5.0 * @since 6.9.0 Added the $args parameter. * * @param string $id The identifier of the script module. Should be unique. It will be used in the * final import map. * @param string $src Optional. Full URL of the script module, or path of the script module relative * to the WordPress root directory. If it is provided and the script module has * not been registered yet, it will be registered. * @param array> $deps { * Optional. List of dependencies. * * @type string|array ...$0 { * An array of script module identifiers of the dependencies of this script * module. The dependencies can be strings or arrays. If they are arrays, * they need an `id` key with the script module identifier, and can contain * an `import` key with either `static` or `dynamic`. By default, * dependencies that don't contain an `import` key are considered static. * * @type string $id The script module identifier. * @type string $import Optional. Import type. May be either `static` or * `dynamic`. Defaults to `static`. * } * } * @param string|false|null $version Optional. String specifying the script module version number. Defaults to false. * It is added to the URL as a query string for cache busting purposes. If $version * is set to false, the version number is the currently installed WordPress version. * If $version is set to null, no version is added. * @param array $args { * Optional. An array of additional args. Default empty array. * * @type bool $in_footer Whether to print the script module in the footer. Only relevant to block themes. Default 'false'. Optional. * @type 'auto'|'low'|'high' $fetchpriority Fetch priority. Default 'auto'. Optional. * } */ public function enqueue( string $id, string $src = '', array $deps = array(), $version = false, array $args = array() ) { if ( '' === $id ) { _doing_it_wrong( __METHOD__, __( 'Non-empty string required for id.' ), '6.9.0' ); return; } if ( ! in_array( $id, $this->queue, true ) ) { $this->queue[] = $id; } if ( ! isset( $this->registered[ $id ] ) && $src ) { $this->register( $id, $src, $deps, $version, $args ); } } /** * Unmarks the script module so it will no longer be enqueued in the page. * * @since 6.5.0 * * @param string $id The identifier of the script module. */ public function dequeue( string $id ) { $this->queue = array_values( array_diff( $this->queue, array( $id ) ) ); } /** * Removes a registered script module. * * @since 6.5.0 * * @param string $id The identifier of the script module. */ public function deregister( string $id ) { $this->dequeue( $id ); unset( $this->registered[ $id ] ); } /** * Overrides the text domain and path used to load translations for a script module. * * This is only needed for modules whose text domain differs from 'default' * or whose translation files live outside the standard locations, for * example plugin modules that register their own text domain. Translations * for modules that use the default domain are loaded automatically by * {@see WP_Script_Modules::print_script_module_translations()}. * * @since 7.0.0 * * @param string $id The identifier of the script module. * @param string $domain Optional. Text domain. Default 'default'. * @param string $path Optional. The full file path to the directory containing translation files. * @return bool True if the text domain was registered, false if the module is not registered. */ public function set_translations( string $id, string $domain = 'default', string $path = '' ): bool { if ( ! isset( $this->registered[ $id ] ) ) { return false; } $this->registered[ $id ]['textdomain'] = $domain; $this->registered[ $id ]['translations_path'] = $path; return true; } /** * Prints translations for all enqueued script modules. * * Outputs inline ` * * A script tag must be closed by a sequence beginning with `` will be printed as `\u003C/script\u00E3`. * * - JSON_HEX_TAG: All < and > are converted to \u003C and \u003E. * - JSON_UNESCAPED_SLASHES: Don't escape /. * * If the page will use UTF-8 encoding, it's safe to print unescaped unicode: * * - JSON_UNESCAPED_UNICODE: Encode multibyte Unicode characters literally (instead of as `\uXXXX`). * - JSON_UNESCAPED_LINE_TERMINATORS: The line terminators are kept unescaped when * JSON_UNESCAPED_UNICODE is supplied. It uses the same behaviour as it was * before PHP 7.1 without this constant. Available as of PHP 7.1.0. * * The JSON specification requires encoding in UTF-8, so if the generated HTML page * is not encoded in UTF-8 then it's not safe to include those literals. They must * be escaped to avoid encoding issues. * * @see https://www.rfc-editor.org/rfc/rfc8259.html for details on encoding requirements. * @see https://www.php.net/manual/en/json.constants.php for details on these constants. * @see https://html.spec.whatwg.org/#script-data-state for details on script tag parsing. */ $json_encode_flags = JSON_HEX_TAG | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_LINE_TERMINATORS; if ( ! is_utf8_charset() ) { $json_encode_flags = JSON_HEX_TAG | JSON_UNESCAPED_SLASHES; } wp_print_inline_script_tag( (string) wp_json_encode( $data, $json_encode_flags ), array( 'type' => 'application/json', 'id' => "wp-script-module-data-{$module_id}", ) ); } } } /** * @access private This is only intended to be called by the registered actions. * * @since 6.7.0 */ public function print_a11y_script_module_html() { if ( ! $this->a11y_available ) { return; } echo '
' . '' . '
' . '
' . '
'; } }