ag::sanitize_rules(), array( 'noscript' => array(), 'iframe' => array( 'src' => array(), 'height' => array(), 'width' => array(), 'style' => array(), 'aria-hidden' => array(), ), ) ) ); } finally { // finally, so an exception inside the sink cannot leave the site's CSS // allow-list widened for the rest of the request. remove_filter( 'safe_style_css', array( self::class, 'allow_iframe_hiding_styles' ) ); } } /** * Adds the two declarations the noscript iframe's inline style needs to the * wp_kses() CSS allow-list. * * Public and static only because add_filter()/remove_filter() must be handed * the same callable, and WordPress invokes it from outside this class. It is * NOT a hook to register anywhere: the_tag() adds it immediately before its * own wp_kses() call and removes it immediately after, which is the whole * point - see the comment there. * * @param mixed $styles The CSS property allow-list wp_kses() is about to use. * @return array The allow-list plus `display` and `visibility`. */ public static function allow_iframe_hiding_styles( $styles ): array { $styles = is_array( $styles ) ? $styles : array(); $styles[] = 'display'; $styles[] = 'visibility'; return $styles; } /** * Outputs the noscript/iframe container code right after the opening body tag. * * @return void */ public function body_open(): void { $placement = $this->options->get( GTM4WP_OPTION_GTM_PLACEMENT ); if ( ( GTM4WP_PLACEMENT_BODYOPEN === $placement ) || ( GTM4WP_PLACEMENT_BODYOPEN_AUTO === $placement ) ) { $this->the_tag(); } } /** * Inserts the GTM noscript/iframe code in the footer if code placement is set to Footer. * * @return void */ public function footer(): void { if ( GTM4WP_PLACEMENT_FOOTER === $this->options->get( GTM4WP_OPTION_GTM_PLACEMENT ) ) { $this->the_tag(); } } /** * Excludes the dataLayer variable and gtm4wp* variables from being combined * into the minified JS file by WP Rocket. * * @param array $pattern Patterns to match in inline JS content. * @return array Patterns extended with the GTM4WP entries. */ public function rocket_excluded_inline_js_content( $pattern ) { $pattern[] = 'dataLayer'; $pattern[] = 'gtm4wp'; // The consent block names neither once it pushes to a custom data layer // name (#325, RI-34); a fixed plugin token, never the user's identifier. $pattern[] = ConsentDefaults::CONSENT_DEFAULT_COMMAND; return $pattern; } /** * Returns the normalized container rows of the GTM4WP_OPTION_GTM_CONTAINERS * option: one row per container with its own environment parameters, * custom domain and custom path. * * @return array> */ private function containers(): array { return ContainerRows::normalize( $this->options->get( GTM4WP_OPTION_GTM_CONTAINERS, array() ) ); } /** * Kill switch: decides whether the GTM container code (the loader * and the