settings = $settings;
$this->classifier = $scanner->classifier;
}
/**
* Start buffering on front-end HTML requests.
*/
public function register() {
add_action( 'template_redirect', array( $this, 'start' ), 0 );
}
/**
* Begin the buffer when this request should be filtered.
*/
public function start() {
if ( $this->should_filter() ) {
ob_start( array( $this, 'filter' ) );
}
}
/**
* Requests that must never be altered.
*
* @return bool
*/
private function should_filter() {
if ( Skip::request() ) {
return false; // Back office, staff and integration pages: never buffered or rewritten.
}
if ( is_admin() || wp_doing_ajax() || wp_doing_cron() || is_feed() || is_embed() || is_customize_preview() ) {
return false;
}
if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
return false;
}
if ( Scanner::is_scan_request() ) {
return false;
}
// Page-builder editing screens.
foreach ( array( 'fl_builder', 'elementor-preview', 'et_fb', 'vc_editable', 'bricks', 'ct_builder', 'brizy-edit-iframe' ) as $key ) {
if ( isset( $_GET[ $key ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- presence check only.
return false;
}
}
/**
* Filter whether GoConsent filters this page's HTML.
*
* @param bool $filter Default true.
*/
return (bool) apply_filters( 'goconsent_filter_page', true );
}
/**
* Output-buffer callback. Fails open: on any error the page is served unchanged.
*
* @param string $html Page HTML.
* @return string
*/
public function filter( $html ) {
if ( ! is_string( $html ) || '' === $html ) {
return $html;
}
$head = substr( $html, 0, 2000 );
if ( false === stripos( $head, 'settings->get( 'block' ) ) {
$out = $this->hold_scripts( $out );
$out = $this->strip_noscript_pixels( $out );
}
$out = MapsGate::rewrite( $out );
$out = ClickToLoad::rewrite( $out );
$out = LocalFonts::rewrite( $out );
return ( is_string( $out ) && '' !== $out ) ? $out : $html;
} catch ( \Throwable $e ) {
if ( defined( 'WP_DEBUG' ) && WP_DEBUG && defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- debug-only diagnostics.
error_log( 'GoConsent output filter: ' . $e->getMessage() );
}
return $html;
}
}
/**
* Neutralise analytics/advertising scripts until consent (type="text/plain").
*
* @param string $html HTML.
* @return string
*/
private function hold_scripts( $html ) {
$out = preg_replace_callback( '##is', array( $this, 'rewrite_script' ), $html );
return null === $out ? $html : $out;
}
/**
* Rewrite one script tag.
*
* @param array $m Regex match.
* @return string
*/
public function rewrite_script( $m ) {
$attrs = $m[1];
if ( false !== stripos( $attrs, 'data-goconsent' ) ) {
return $m[0];
}
$type = '';
if ( preg_match( '#\btype\s*=\s*(["\']?)([^"\'\s>]+)\1#i', $attrs, $tm ) ) {
$type = strtolower( $tm[2] );
}
if ( '' !== $type && ! in_array( $type, array( 'text/javascript', 'application/javascript', 'module' ), true ) ) {
return $m[0];
}
$cat = $this->classifier->category( $attrs . ' ' . $m[2], $attrs );
if ( '' === $cat || 'necessary' === $cat ) {
return $m[0];
}
$attrs = preg_replace( '#\s*\btype\s*=\s*(["\']?)[^"\'\s>]+\1#i', '', $attrs );
$extra = ' type="text/plain" data-goconsent="' . $cat . '"' . ( 'module' === $type ? ' data-goconsent-type="module"' : '' );
return '';
}
/**
* Tracking pixels inside