ner loader in
// header_begin(); this iframe is the same container by another route,
// so it has to go with it. It used to be emitted regardless, which
// meant an excluded user still loaded the container (and was counted
// in the reports) whenever JavaScript was unavailable - the exact
// case the noscript iframe exists for. Mark the code as "written" so
// the iframe block below is skipped, exactly like placement OFF and
// the kill switch above; the data layer stays active.
$GLOBALS['gtm4wp_container_code_written'] = true;
if ( ! $no_console_log ) {
$_gtm_tag .= $this->disabled_role_warning( $excluded_role );
}
}
if ( ( array() !== $containers ) && ( ! ( $GLOBALS['gtm4wp_container_code_written'] ?? false ) ) ) {
foreach ( $containers as $one_container ) {
$one_gtm_id = (string) ( $one_container[ ContainerRows::COLUMN_ID ] ?? '' );
// esc_attr() per PART below, at the point of injection (#225). Each part
// is already allow-list validated - the id by the pattern one line down,
// the domain by container_domain()'s FILTER_VALIDATE_DOMAIN fallback, the
// environment values inside container_environment() - so esc_attr() is
// the identity function on everything the validators pass today and
// exists for the day a pattern is widened. NOT esc_attr()/esc_url() over
// the whole src: the environment fragment joins with raw '&' on purpose
// (wp_kses encodes it to & at output, the 1.x byte form), and
// gtm4wp_get_the_gtm_tag() returns this string as public 1.x API -
// pre-encoding it would change those bytes and hand third-party
// consumers an already-escaped value to double-escape (RI-4).
if ( preg_match( ContainerRows::GTM_ID_PATTERN, $one_gtm_id ) ) {
$_gtm_tag .= '
';
}
}
$_gtm_tag .= '
';
$GLOBALS['gtm4wp_container_code_written'] = true;
}
return $_gtm_tag;
}
/**
* Outputs a HTML code that includes the noscript/iframe part of the Google Tag Manager container.
*
* @return void
*/
public function the_tag(): void {
// The iframe's inline style needs `display` and `visibility`. Whether
// safecss_filter_attr() strips those depends on the WordPress version:
// core added `display` to the safe_style_css default list in 7.0 and
// `visibility` in 7.1, so on 6.3-6.9 both are stripped and on 7.0
// `visibility` still is. While the floor is 6.3 this filter is
// load-bearing, not belt-and-braces - drop it only in the change that
// raises the floor past 7.1, never as a "core allows it now" cleanup.
//
// Widen the CSS allow-list around THIS wp_kses() call only, then put it back:
// safe_style_css is a global WordPress control, so a filter left
// registered would relax it for every other wp_kses()/wp_kses_post() call
// in the same request - including wp_filter_post_kses on content saved by
// users without unfiltered_html, and a REST save is not is_admin(). One
// line of our own markup is not a reason to loosen the rule site-wide.
add_filter( 'safe_style_css', array( self::class, 'allow_iframe_hiding_styles' ) );
try {
// print_markup_block(), not a bare wp_kses(): this block mixes the noscript
// iframe (whose src must keep its & entity form) with the console
// warning