Skip to content

Commit c2c3da4

Browse files
wpgauravclaude
andcommitted
v1.4.2: preserve data-* and module attributes on snippet tags
wp_kses was stripping data-website-id, data-id, async, defer, nomodule, and other valid attributes from script/style/link tags in Header & Footer snippets for non-admin users. Unified the two separate allowed-tags lists (output and save) into a single snippet_allowed_tags() method. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 411d7a4 commit c2c3da4

5 files changed

Lines changed: 96 additions & 64 deletions

File tree

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
All-in-one WordPress optimization toolkit with 15+ modules for performance, security, SEO, and content management. Built with modern WordPress coding standards and a clean module-based dashboard. Optimized for performance with lazy-loading, static property caching, and intelligent transients.
44

5-
**Version:** 1.4.0
5+
**Version:** 1.4.2
66
**License:** GPL-2.0-or-later
77
**Text Domain:** `functionalities`
88
**Pricing:** Free
@@ -427,6 +427,17 @@ Example module definition:
427427

428428
## Changelog
429429

430+
### 1.4.2
431+
- **Fixed**: `wp_kses` now preserves `data-*` attributes on `<script>`, `<style>`, and `<link>` tags in Header & Footer snippets.
432+
- **Fixed**: `async`, `defer`, `nomodule`, `id`, `nonce`, `crossorigin`, and `as` attributes no longer stripped from snippet tags for non-admin users.
433+
- **Fixed**: Unified allowed-tags list between snippet output and save sanitization to prevent attribute drift.
434+
435+
### 1.4.1
436+
- **Added**: Opt-in "Delete all plugin data when uninstalling" checkbox on the dashboard.
437+
- **Fixed**: Replaced all direct `file_put_contents` calls with `WP_Filesystem` API.
438+
- **Fixed**: Extracted duplicate CSS sanitization into a shared trait.
439+
- **Fixed**: Removed `sslverify => false` from loopback HTTP requests.
440+
430441
### 1.4.0
431442
- **Added**: Bricks Builder font integration — custom fonts appear in Bricks typography picker and load inside the builder canvas.
432443
- **Added**: PWA module prefills app name, short name, description, and icons from WordPress Settings and Site Icon.

functionalities.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Plugin Name: Dynamic Functionalities
44
* Plugin URI: https://functionalities.dev
55
* Description: All-in-one WordPress optimization toolkit. 15+ modules for performance, security, SEO, and content management.
6-
* Version: 1.4.1
6+
* Version: 1.4.2
77
* Author: Gaurav Tiwari
88
* Author URI: https://gauravtiwari.org
99
* License: GPL-2.0-or-later
@@ -19,7 +19,7 @@
1919

2020
// Define constants.
2121
if (!defined('FUNCTIONALITIES_VERSION')) {
22-
define('FUNCTIONALITIES_VERSION', '1.4.1');
22+
define('FUNCTIONALITIES_VERSION', '1.4.2');
2323
}
2424
if (!defined('FUNCTIONALITIES_FILE')) {
2525
define('FUNCTIONALITIES_FILE', __FILE__);

includes/admin/trait-admin-sanitizers.php

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -152,15 +152,7 @@ public static function sanitize_snippets( $input ) : array {
152152
$out['ga4_id'] = $ga4;
153153
}
154154

155-
$allowed_tags = array(
156-
'script' => array( 'src' => true, 'type' => true, 'async' => true, 'defer' => true, 'crossorigin' => true, 'integrity' => true, 'data-*' => true ),
157-
'style' => array( 'type' => true, 'media' => true ),
158-
'link' => array( 'rel' => true, 'href' => true, 'as' => true, 'crossorigin' => true, 'media' => true, 'type' => true ),
159-
'meta' => array( 'name' => true, 'content' => true, 'property' => true, 'http-equiv' => true ),
160-
'noscript' => array(),
161-
'div' => array( 'id' => true, 'class' => true, 'style' => true ),
162-
'span' => array( 'id' => true, 'class' => true, 'style' => true ),
163-
);
155+
$allowed_tags = \Functionalities\Features\Snippets::snippet_allowed_tags();
164156

165157
foreach ( array( 'header', 'body_open', 'footer' ) as $location ) {
166158
if ( empty( $input[ $location ] ) || ! \is_array( $input[ $location ] ) ) {

includes/features/class-snippets.php

Lines changed: 71 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* @package Functionalities
1010
* @subpackage Features
1111
* @since 0.2.0
12-
* @version 1.4.0
12+
* @version 1.4.2
1313
*/
1414

1515
namespace Functionalities\Features;
@@ -373,6 +373,75 @@ public static function output_body_open() : void {
373373
self::output_snippets( 'body_open', 'functionalities_snippets_body_open_code', 'Custom Body Open Code' );
374374
}
375375

376+
/**
377+
* Allowed HTML tags and attributes for code snippets.
378+
*
379+
* Single source of truth used by both escape_snippet() (output) and
380+
* sanitize_snippets() (save) to ensure consistent filtering.
381+
*
382+
* @since 1.4.2
383+
*
384+
* @return array Allowed tags array for wp_kses().
385+
*/
386+
public static function snippet_allowed_tags(): array {
387+
return array(
388+
'script' => array(
389+
'type' => true,
390+
'src' => true,
391+
'async' => true,
392+
'defer' => true,
393+
'id' => true,
394+
'crossorigin' => true,
395+
'integrity' => true,
396+
'nonce' => true,
397+
'nomodule' => true,
398+
'data-*' => true,
399+
),
400+
'noscript' => array(),
401+
'style' => array(
402+
'type' => true,
403+
'media' => true,
404+
'id' => true,
405+
'nonce' => true,
406+
'data-*' => true,
407+
),
408+
'link' => array(
409+
'rel' => true,
410+
'href' => true,
411+
'type' => true,
412+
'media' => true,
413+
'as' => true,
414+
'crossorigin' => true,
415+
'id' => true,
416+
'data-*' => true,
417+
),
418+
'meta' => array(
419+
'name' => true,
420+
'content' => true,
421+
'charset' => true,
422+
'http-equiv' => true,
423+
'property' => true,
424+
),
425+
'img' => array(
426+
'src' => true,
427+
'alt' => true,
428+
'width' => true,
429+
'height' => true,
430+
'loading' => true,
431+
),
432+
'iframe' => array(
433+
'src' => true,
434+
'width' => true,
435+
'height' => true,
436+
'frameborder' => true,
437+
'allow' => true,
438+
'allowfullscreen' => true,
439+
'loading' => true,
440+
'style' => true,
441+
),
442+
);
443+
}
444+
376445
/**
377446
* Escape a code snippet for safe output.
378447
*
@@ -391,56 +460,7 @@ private static function escape_snippet( string $code ): string {
391460
return $code;
392461
}
393462

394-
return self::kses_with_styles(
395-
$code,
396-
array(
397-
'script' => array(
398-
'type' => true,
399-
'src' => true,
400-
'async' => true,
401-
'defer' => true,
402-
'id' => true,
403-
'crossorigin' => true,
404-
'integrity' => true,
405-
'nonce' => true,
406-
),
407-
'noscript' => array(),
408-
'style' => array(
409-
'type' => true,
410-
'media' => true,
411-
),
412-
'link' => array(
413-
'rel' => true,
414-
'href' => true,
415-
'type' => true,
416-
'media' => true,
417-
),
418-
'meta' => array(
419-
'name' => true,
420-
'content' => true,
421-
'charset' => true,
422-
'http-equiv' => true,
423-
'property' => true,
424-
),
425-
'img' => array(
426-
'src' => true,
427-
'alt' => true,
428-
'width' => true,
429-
'height' => true,
430-
'loading' => true,
431-
),
432-
'iframe' => array(
433-
'src' => true,
434-
'width' => true,
435-
'height' => true,
436-
'frameborder' => true,
437-
'allow' => true,
438-
'allowfullscreen' => true,
439-
'loading' => true,
440-
'style' => true,
441-
),
442-
)
443-
);
463+
return self::kses_with_styles( $code, self::snippet_allowed_tags() );
444464
}
445465

446466
/**

readme.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Tags: performance, security, seo, redirection, cleanup
55
Requires at least: 5.8
66
Tested up to: 7.0
77
Requires PHP: 7.4
8-
Stable tag: 1.4.1
8+
Stable tag: 1.4.2
99
License: GPL-2.0-or-later
1010
License URI: https://www.gnu.org/licenses/gpl-2.0.html
1111

@@ -134,6 +134,12 @@ Before uninstalling, go to the Functionalities dashboard and check **"Delete all
134134

135135
== Changelog ==
136136

137+
= 1.4.2 =
138+
* Fixed: `wp_kses` now preserves `data-*` attributes on `<script>`, `<style>`, and `<link>` tags in Header & Footer snippets
139+
* Fixed: `async`, `defer`, `nomodule`, `id`, `nonce`, `crossorigin`, and `as` attributes no longer stripped from snippet tags for non-admin users
140+
* Fixed: Unified allowed-tags list between snippet output and save sanitization to prevent attribute drift
141+
* Fixed: README.md version was outdated (still showed 1.4.0)
142+
137143
= 1.4.1 =
138144
* Added: Opt-in "Delete all plugin data when uninstalling" checkbox on the dashboard — removes all options, post metadata, transients, and files on uninstall
139145
* Fixed: Replaced all direct file_put_contents calls with WP_Filesystem API across Task Manager, Redirect Manager, and JSON file creation
@@ -253,6 +259,9 @@ Before uninstalling, go to the Functionalities dashboard and check **"Delete all
253259

254260
== Upgrade Notice ==
255261

262+
= 1.4.2 =
263+
Fixes `data-*` and other attributes being stripped from script/style/link tags in Header & Footer snippets for non-admin users.
264+
256265
= 1.4.1 =
257266
Code quality and plugin review compliance: WP_Filesystem for all file writes, comprehensive uninstall cleanup (opt-in), shared CSS sanitization trait, and minor fixes.
258267

0 commit comments

Comments
 (0)