

/**
 * Disable WordPress emoji scripts and styles
 */
function disable_wp_emojis() {
    remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
    remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );

    remove_action( 'wp_print_styles', 'print_emoji_styles' );
    remove_action( 'admin_print_styles', 'print_emoji_styles' );

    remove_filter( 'the_content_feed', 'wp_staticize_emoji' );
    remove_filter( 'comment_text_rss', 'wp_staticize_emoji' );
    remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );

    add_filter( 'tiny_mce_plugins', function( $plugins ) {
        return is_array( $plugins ) ? array_diff( $plugins, array( 'wpemoji' ) ) : array();
    });

    add_filter( 'emoji_svg_url', '__return_false' );
}
add_action( 'init', 'disable_wp_emojis' );


function remove_wp_emoji_loader() {
    wp_dequeue_script( 'wp-emoji-release' );
    wp_deregister_script( 'wp-emoji-release' );
}
add_action( 'wp_enqueue_scripts', 'remove_wp_emoji_loader', 100 );




/**
 * CSP Nonce Injection
 * Generates a per-request nonce, sends the CSP header with it,
 * and stamps every inline <script> tag with that nonce via
 * output buffering (init -> shutdown strategy).
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit; // No direct access.
}

/**
 * 1. Generate one cryptographically random nonce per request,
 *    stored so it's available everywhere (header + buffer rewrite).
 */
function ion_get_csp_nonce() {
	static $nonce = null;
	if ( $nonce === null ) {
		$nonce = base64_encode( random_bytes( 16 ) );
	}
	return $nonce;
}

/**
 * 2. Send the CSP header as early as possible.
 *    'strict-dynamic' + nonce covers GTM's dynamically injected tags;
 *    the explicit domain list is the fallback for older browsers
 *    that don't understand strict-dynamic.
 */
add_action( 'send_headers', function () {
	$nonce = ion_get_csp_nonce();

	$csp = "script-src 'self' 'nonce-{$nonce}' 'strict-dynamic'";

	header( "Content-Security-Policy: {$csp}" );
	// While testing, swap the line above for this one instead —
	// it logs violations without blocking anything:
	// header( "Content-Security-Policy-Report-Only: {$csp}" );
} );

/**
 * 3. Start an output buffer at init, so we can rewrite the final
 *    HTML before it's sent to the browser.
 */
add_action( 'init', function () {
	ob_start( 'ion_inject_csp_nonce' );
} );

/**
 * 4. Buffer callback: stamp EVERY <script> tag with the nonce —
 *    inline AND external (src=...) alike.
 *
 *    Why: with 'strict-dynamic' in the CSP, host-based allowlisting
 *    (including 'self') is disabled entirely per spec. The ONLY thing
 *    that makes a script trusted is a matching nonce, or being injected
 *    by another already-trusted nonced script. So plugin/theme scripts
 *    enqueued the normal WP way (<script src="...">) need the nonce
 *    too, not just hand-written inline <script> blocks.
 */
function ion_inject_csp_nonce( $html ) {
	$nonce = ion_get_csp_nonce();

	// Match any <script ...> opening tag.
	$pattern = '/<script\b([^>]*)>/i';

	$html = preg_replace_callback( $pattern, function ( $matches ) use ( $nonce ) {
		// Don't double-stamp if a nonce is already present somehow.
		if ( stripos( $matches[1], 'nonce=' ) !== false ) {
			return $matches[0];
		}
		return '<script' . $matches[1] . ' nonce="' . esc_attr( $nonce ) . '">';
	}, $html );

	return $html;
}

/**
 * 5. Belt-and-suspenders: also nonce scripts via WP's own enqueue
 *    filter. Covers any case where a plugin's tag doesn't get caught
 *    cleanly by the buffer regex above (unusual attribute formatting,
 *    scripts printed after the buffer closes, etc.)
 */
add_filter( 'script_loader_tag', function ( $tag, $handle, $src ) {
	if ( strpos( $tag, 'nonce=' ) !== false ) {
		return $tag; // Already has one (e.g. from the buffer pass).
	}
	$nonce = ion_get_csp_nonce();
	return str_replace( '<script ', '<script nonce="' . esc_attr( $nonce ) . '" ', $tag );
}, 10, 3 );

/**
 * 5. Flush the buffer at shutdown.
 */
add_action( 'shutdown', function () {
	if ( ob_get_level() > 0 ) {
		ob_end_flush();
	}
}, 0 );<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="//www.timgroup.com/wp-content/plugins/wordpress-seo/css/main-sitemap.xsl"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
	<sitemap>
		<loc>https://www.timgroup.com/post-sitemap.xml</loc>
		<lastmod>2019-04-03T15:08:35+00:00</lastmod>
	</sitemap>
	<sitemap>
		<loc>https://www.timgroup.com/page-sitemap.xml</loc>
		<lastmod>2026-09-09T13:28:02+00:00</lastmod>
	</sitemap>
	<sitemap>
		<loc>https://www.timgroup.com/attachment-sitemap.xml</loc>
		<lastmod>2025-06-11T13:58:41+00:00</lastmod>
	</sitemap>
	<sitemap>
		<loc>https://www.timgroup.com/awards-sitemap.xml</loc>
		<lastmod>2021-04-07T04:11:12+00:00</lastmod>
	</sitemap>
	<sitemap>
		<loc>https://www.timgroup.com/category-sitemap.xml</loc>
		<lastmod>2019-04-03T15:08:35+00:00</lastmod>
	</sitemap>
	<sitemap>
		<loc>https://www.timgroup.com/post_tag-sitemap.xml</loc>
		<lastmod>2018-10-11T16:31:37+00:00</lastmod>
	</sitemap>
	<sitemap>
		<loc>https://www.timgroup.com/regions-sitemap.xml</loc>
		<lastmod>2021-04-07T04:11:12+00:00</lastmod>
	</sitemap>
	<sitemap>
		<loc>https://www.timgroup.com/when-published-sitemap.xml</loc>
		<lastmod>2021-04-07T04:11:12+00:00</lastmod>
	</sitemap>
	<sitemap>
		<loc>https://www.timgroup.com/author-sitemap.xml</loc>
		<lastmod>2025-06-11T14:11:39+00:00</lastmod>
	</sitemap>
</sitemapindex>
<!-- XML Sitemap generated by Yoast SEO -->