tag from executing, and letting * something on the client release it later. * * Two features need exactly this. `DelayJs` holds aBlocks' own scripts back * until the first user interaction; the cookie-consent addon holds third-party * tags back until consent for their category is granted. Both do the same three * things — decide whether a tag is in scope, rewrite its type so the browser * parses but does not run it, and release it later — so the rewriting lives * here once rather than as two independent regexes over every script on the * page. * * The rewrite is deliberately textual. `script_loader_tag` hands over a string, * and the consent addon's second layer works on already-rendered markup, so a * DOM-based rewrite is not available in either caller. */ class ScriptGate { /** * Marker type written into the tag, e.g. `ablocks/delayed` or `text/plain`. * * @var string */ private $type; /** * `( $handle, $src, $tag ) => bool` — whether this tag is in scope. * * @var callable */ private $in_scope; /** * `( $handle, $src ) => array` — extra attributes to write onto the tag. * * @var callable|null */ private $attributes; /** * Whether to move `src` out of the way as well as changing the type. * * @var bool */ private $move_src; public function __construct( $type, callable $in_scope, $attributes = null, $move_src = false ) { $this->type = $type; $this->in_scope = $in_scope; $this->attributes = $attributes; $this->move_src = (bool) $move_src; } /** * Start filtering enqueued script tags. * * @param int $priority Filter priority. */ public function hook( $priority = 20 ) { add_filter( 'script_loader_tag', [ $this, 'filter_tag' ], $priority, 3 ); } /** * @param string $tag Rendered script tag. * @param string $handle Script handle. * @param string $src Script source. * @return string */ public function filter_tag( $tag, $handle, $src ) { if ( ! call_user_func( $this->in_scope, $handle, $src, $tag ) ) { return $tag; } $attrs = $this->attributes ? (array) call_user_func( $this->attributes, $handle, $src ) : []; return self::rewrite_tag( $tag, $this->type, $attrs, $this->move_src ); } /** * Rewrite one script tag so the browser will not execute it. * * A `