File: /wordpress/plugins/wp-cloud-client/1.1.8/src/Cleanup/GtmCleanup.php
<?php
declare(strict_types=1);
namespace VPlugins\WPCloudClient\Cleanup;
use VPlugins\WPCloudClient\Support\Logger;
/**
* One-time removal of GTM-5VJ33FV6 from WPCode / Insert Headers and Footers options.
*
* WSP-3395: GTM-5VJ33FV6 was injected into customer sites via the Insert Headers and
* Footers (WPCode) plugin. This class surgically strips it from the ihaf_insert_header,
* ihaf_insert_body, and ihaf_insert_footer options, preserving any other scripts present.
* It runs exactly once per site via Plugin::activate() and sets a flag so it never repeats.
*/
final class GtmCleanup {
private const GTM_ID = 'GTM-5VJ33FV6';
private const CLEANUP_FLAG = 'wpcc_gtm_cleanup_done';
/**
* Constructor.
*
* @param Logger $logger The logger instance.
*/
public function __construct(
private readonly Logger $logger,
) {}
/**
* Scan ihaf_insert_header/body/footer and strip GTM-5VJ33FV6 from any that contain it.
*
* Exits early without flagging if the cleanup flag is already set or neither WPCode
* plugin variant is active (deferred to the next activation when the plugin is present).
* Surgically strips the GTM block so any surrounding scripts are preserved. Sets the
* cleanup flag only after a successful pass so the method never re-runs.
*
* @return void
*/
public function run(): void {
if ( get_option( self::CLEANUP_FLAG ) ) {
return;
}
if ( ! function_exists( 'is_plugin_active' ) ) {
if ( ! defined( 'ABSPATH' ) || ! file_exists( ABSPATH . 'wp-admin/includes/plugin.php' ) ) {
$this->logger->error( 'GTM cleanup skipped — wp-admin/includes/plugin.php unavailable' );
return;
}
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
if (
! is_plugin_active( 'insert-headers-and-footers/ihaf.php' ) &&
! is_plugin_active( 'insert-headers-and-footers/wpcode.php' )
) {
return;
}
foreach ( [ 'ihaf_insert_header', 'ihaf_insert_body', 'ihaf_insert_footer' ] as $option_name ) {
$value = get_option( $option_name );
// false = option does not exist; skip silently.
if ( false === $value || '' === $value ) {
continue;
}
if ( ! is_string( $value ) ) {
$this->logger->warning(
'GTM cleanup: unexpected option type',
[
'option' => $option_name,
'type' => gettype( $value ),
]
);
continue;
}
if ( ! str_contains( $value, self::GTM_ID ) ) {
continue;
}
$stripped = trim( $this->stripGtmSnippet( $value ) );
if ( '' === $stripped ) {
if ( ! delete_option( $option_name ) ) {
$this->logger->error( 'GTM cleanup: failed to delete ' . $option_name );
return;
}
} elseif ( ! update_option( $option_name, $stripped ) ) {
$this->logger->error( 'GTM cleanup: failed to update ' . $option_name );
return;
}
}
if ( ! update_option( self::CLEANUP_FLAG, 1 ) ) {
$this->logger->error( 'GTM cleanup: failed to set cleanup flag' );
return;
}
$this->logger->info( 'GTM cleanup completed successfully' );
}
/**
* Strip GTM-5VJ33FV6 script blocks from the given value, preserving any surrounding content.
*
* Handles the standard WPCode comment-wrapped format and bare script blocks.
* GTM script bodies do not contain literal < characters, so [^<]* is safe and avoids
* crossing into adjacent script tags.
*
* @param string $value Raw option value from Insert Headers and Footers.
* @return string The value with GTM blocks removed.
*/
private function stripGtmSnippet( string $value ): string {
// Comment-wrapped GTM script block (standard WPCode/IHAF format)
$value = (string) preg_replace(
'/<!--\s*Google Tag Manager\s*-->[\s\S]*?<!--\s*End Google Tag Manager\s*-->/i',
'',
$value
);
// Comment-wrapped GTM noscript block
$value = (string) preg_replace(
'/<!--\s*Google Tag Manager \(noscript\)\s*-->[\s\S]*?<!--\s*End Google Tag Manager \(noscript\)\s*-->/i',
'',
$value
);
// Bare <script> block — GTM scripts contain no < in their body so [^<]* won't cross tag boundaries
$value = (string) preg_replace(
'/<script\b[^>]*>[^<]*' . preg_quote( self::GTM_ID, '/' ) . '[^<]*<\/script>/i',
'',
$value
);
return $value;
}
}