Using wp_add_inline_script() for inline scripts
-
I noticed that in cfturnstile_force_render() the Turnstile render code is currently output using a raw <script>…</script>block.
add_action("cfturnstile_after_field", "cfturnstile_force_render", 10, 1);
function cfturnstile_force_render($unique_id = '') {
if(function_exists('cfturnstile_is_block_based_checkout') && cfturnstile_is_block_based_checkout()) {
return;
}
$unique_id = sanitize_text_field($unique_id);
$key = sanitize_text_field(get_option('cfturnstile_key'));
if($unique_id) {
?>
<script>document.addEventListener("DOMContentLoaded", function() { setTimeout(function(){ var e=document.getElementById("cf-turnstile<?php echo esc_html($unique_id); ?>"); e&&!e.innerHTML.trim()&&(turnstile.remove("#cf-turnstile<?php echo esc_html($unique_id); ?>"), turnstile.render("#cf-turnstile<?php echo esc_html($unique_id); ?>", {sitekey:"<?php echo esc_html($key); ?>"})); }, 0); });</script>
<?php
}
}Would you consider switching that to wp_add_inline_script() tied to a registered/enqueued handle?
This approach has a few advantages:
- Better compatibility with Content Security Policy – inline scripts tied to a handle are easier to identify, hash, or nonce in a CSP-aware environment.
- Hook-safe placement – WordPress handles script placement in the head or footer without echoing directly in the middle of output.
- Dependency management – you can attach it to a handle that depends on any scripts it needs, ensuring the code runs after them.
- Cleaner output – no mixing of PHP and raw HTML script tags, which improves maintainability.
For example:
wp_register_script( 'cfturnstile-inline', false, [], null, true );
wp_enqueue_script( 'cfturnstile-inline' );
$code = 'document.addEventListener("DOMContentLoaded",function(){ … });';
wp_add_inline_script( 'cfturnstile-inline', $code, 'after' );Functionally it behaves the same, but it makes the snippet part of the normal WordPress script queue.
Thanks for considering this — it would make it much easier for CSP-hardened installs to use the plugin without having to special-case the inline block.
I have a filter so that every time an inline script is added via wp_add_inline_script(), I am able to tag the script with ‘data-owner=”my-tag and data-cspid=random session token’. Then in my mu-plugin which generates hashes for inline scripts, I am easily able to pick out all the safe inline scripts by looking for that tag.
What I need to do now is something like this when I look at the inline scripts in the final html:// Allow: your tagged inlines, Rocket placeholders/loader, Rocket IE snippet.
$tok = preg_quote( DBTN_CSP_TOKEN, '#' );
$is_ours = preg_match( '#\bdata-owner=["\']dbtn["\']#i', $attrs )
&& preg_match( '#\bdata-cspid=["\']' . $tok . '["\']#i', $attrs );
$is_rocket_lazy = stripos( $attrs, 'rocketlazyloadscript' ) !== false;
$is_rocket_loader = stripos( $body, 'RocketLazyLoadScripts' ) !== false;
$is_rocket_ie = strpos( $body, 'nowprocket=1' ) !== false
&& strpos( $body, 'navigator.userAgent.match(/MSIE' ) !== false;
$sitekey = '0xmysitekey';
$looks_like_turnstile = (
// uses Turnstile API
preg_match('#\bturnstile\.(?:render|remove)\s*\(#', $body)
// targets your known element
&& strpos($body, 'cf-turnstile-woo-checkout') !== false
// carries your exact sitekey
&& preg_match('#"sitekey"\s*:\s*"' . preg_quote($sitekey, '#') . '"#', $body)
// no obviously dangerous tokens
&& !preg_match('#\b(?:eval|Function|innerHTML\s*=|document\.write)\b#', $body)
);
if ( ! ( $is_ours || $is_rocket_lazy || $is_rocket_loader || $is_rocket_ie || $looks_like_turnstile ) ) {
continue;
}
$hashes_a[] = "'sha256-" . base64_encode( hash( 'sha256', $body, true ) ) . "'";Thanks for considering this — it would make it much easier for CSP-hardened installs to use the plugin without having to special-case the inline block.
Best
The topic ‘Using wp_add_inline_script() for inline scripts’ is closed to new replies.