Skip to content

Conversation

@Arukuen
Copy link
Contributor

@Arukuen Arukuen commented Jan 20, 2026

…ist block

fixes #3673
fixes #3674

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced Block Defaults configuration section in Editor Settings for managing default block behaviors
    • Heading blocks now support theme margin defaults with separate configuration for posts and non-posts content types
    • Icon List blocks support customizable default icon assignment
  • Chores

    • Enhanced icon settings with SVG sanitization for security compliance

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 20, 2026

📝 Walkthrough

Walkthrough

This pull request introduces configurable default behaviors for Heading and Icon-list blocks. It adds settings for heading theme margins initialization based on post type, icon-list default icon configuration, and corresponding admin UI controls with SVG sanitization for secure icon storage.

Changes

Cohort / File(s) Summary
Block Initialization Logic
src/block/heading/edit.js, src/block/icon-list/edit.js
Introduced useEffect hooks with post-type-aware initialization. Heading blocks now default useThemeTextMargins based on post type and stackable settings. Icon-list blocks initialize icon from settings with fallback.
Icon-list Schema
src/block/icon-list/schema.js
Changed default icon value from DEFAULT_SVG to empty string to enable detection of unset attributes; updated import accordingly.
Admin UI Components
src/components/admin-icon-setting/index.js, src/components/admin-icon-setting/editor.scss
New AdminIconSetting component for icon management in admin UI. Added SCSS styling with custom property for accent color.
IconControl Enhancement
src/components/icon-control/index.js
Wired allowReset prop through to BaseControl; exposed as part of defaultProps instead of hardcoded constant.
Backend Settings
src/editor-settings.php
Added three new settings registrations: heading default margins for posts/non-posts and icon-list default icon. Introduced sanitize_svg_setting() method for secure SVG sanitization.
Admin Settings UI
src/welcome/admin.js
Added new "Block Defaults" settings section with controls for heading margins and icon-list default icon; integrated new AdminIconSetting component.

Sequence Diagram(s)

sequenceDiagram
    participant Block as Heading Block Edit
    participant Effect as useEffect Hook
    participant Select as useSelect (core/editor)
    participant Settings as Stackable Settings
    participant Attr as setAttributes

    Block->>Effect: Component mounts
    Effect->>Select: Query current post type
    Select-->>Effect: Return post type
    Effect->>Settings: Fetch useThemeTextMargins default<br/>(based on post type)
    Settings-->>Effect: Return default margin setting
    alt useThemeTextMargins is undefined/empty
        Effect->>Attr: Set useThemeTextMargins to<br/>determined default
        Attr-->>Block: Update block attributes
    else Already set
        Effect-->>Block: No changes
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 Defaults dance where margins meet,
Icons settle, safe and neat,
Settings bloom in block-wise ways,
SVGs cleansed for safer days!
A rabbit's hop through config bliss

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Out of Scope Changes check ❓ Inconclusive Changes include icon list block default icon feature not mentioned in the provided issue #3673, which appears to be a separate feature from issue #3674. Verify that issue #3674 exists and contains requirements for the icon list block default icon feature to confirm it is in scope.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes: adding block defaults for heading theme margins and an icon setting for the icon list block.
Linked Issues check ✅ Passed The PR implements all requirements from issue #3673: adds two new admin settings for heading theme margins (posts and non-posts) in the Block Defaults section, implements logic to apply defaults on first render, and disables settings by default.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

🤖 Pull request artifacts

file commit
pr3676-stackable-3676-merge.zip 7cae2eb

github-actions bot added a commit that referenced this pull request Jan 20, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/editor-settings.php`:
- Around line 286-298: sanitize_svg_setting currently uses brittle regexes that
miss unquoted event handlers, data: URLs, xlink/href javascript targets, <use>
references and animation elements, and does not handle preg_replace returning
null; update it to perform robust sanitization by either (A) replacing the
ad-hoc regex approach in sanitize_svg_setting with WordPress's wp_kses using a
restrictive SVG-specific allowed tags/attributes whitelist (including removal of
on* attributes regardless of quoting, stripping href/xlink:href values that
start with javascript: or data:, and disallowing <use>, <animate>, <set>), or
(B) if you keep regexes, add patterns to remove unquoted on* attributes, strip
any href/xlink:href attributes whose values begin with javascript: or data:,
remove <use>, <animate>, <set> elements, and after each preg_replace check for
null and handle by returning an empty string or logging and returning safe
output; make these changes inside the sanitize_svg_setting function to ensure
all dangerous patterns are covered.
🧹 Nitpick comments (4)
src/block/icon-list/edit.js (1)

208-213: Missing dependencies in useEffect may cause lint warnings.

The effect references attributes.icon, setAttributes, and settings but has an empty dependency array. While the intent is to run once on mount, this pattern typically triggers React's exhaustive-deps lint rule.

If this is intentional (and linting allows it), consider adding a suppression comment to clarify intent. Otherwise, the pattern used in heading/edit.js (also with empty deps) suggests this is acceptable in this codebase.

Optional: Add lint suppression for clarity
 	// Set icon default value from setting on first load
 	useEffect( () => {
 		if ( attributes.icon === undefined || attributes.icon === '' ) {
 			setAttributes( { icon: settings.stackable_icon_list_block_default_icon || DEFAULT_SVG } )
 		}
+	// eslint-disable-next-line react-hooks/exhaustive-deps
 	}, [] )
src/block/heading/edit.js (1)

91-102: postType is not in the dependency array but is used in the effect.

The effect uses postType from useSelect to determine the default margin setting, but postType is not in the dependency array. While post type rarely changes during editing, if it ever does (e.g., in some custom editor scenarios), the effect won't recalculate.

Given this is an initialization effect meant to run once, and post type switching is extremely rare, this is likely acceptable. Consider adding a comment or lint suppression for clarity.

Optional: Add lint suppression for clarity
 	// Set useThemeTextMargins default value from setting on first load
 	useEffect( () => {
 		if ( attributes.useThemeTextMargins === undefined || attributes.useThemeTextMargins === '' ) {
 			const isPost = postType === 'post'
 
 			const defaultThemeMargins = isPost
 				? !! settings.stackable_enable_heading_default_theme_margins_posts
 				: !! settings.stackable_enable_heading_default_theme_margins_non_posts
 
 			setAttributes( { useThemeTextMargins: defaultThemeMargins } )
 		}
+	// eslint-disable-next-line react-hooks/exhaustive-deps
 	}, [] )
src/editor-settings.php (1)

244-267: Consider using rest_sanitize_boolean for boolean settings.

The new boolean settings use sanitize_text_field as the sanitize callback. While this follows the pattern used elsewhere in this file (lines 84, 132, etc.), using rest_sanitize_boolean (as on line 39) would be more semantically correct for boolean types.

This is a minor consistency issue and doesn't affect functionality since the REST API handles boolean coercion.

Optional: Use rest_sanitize_boolean for boolean settings
 			register_setting(
 				'stackable_editor_settings',
 				'stackable_enable_heading_default_theme_margins_posts',
 				array(
 					'type' => 'boolean',
 					'description' => __( "When enabled, newly added Stackable Heading blocks in Posts will use the theme's default margins automatically.", STACKABLE_I18N ),
-					'sanitize_callback' => 'sanitize_text_field',
+					'sanitize_callback' => 'rest_sanitize_boolean',
 					'show_in_rest' => true,
 					'default' => false,
 				)
 			);

 			register_setting(
 				'stackable_editor_settings',
 				'stackable_enable_heading_default_theme_margins_non_posts',
 				array(
 					'type' => 'boolean',
 					'description' => __( "When enabled, newly added Stackable Heading blocks in non-Post content (Pages and custom post types) will use the theme's default margins automatically.", STACKABLE_I18N ),
-					'sanitize_callback' => 'sanitize_text_field',
+					'sanitize_callback' => 'rest_sanitize_boolean',
 					'show_in_rest' => true,
 					'default' => false,
 				)
 			);
src/components/admin-icon-setting/index.js (1)

16-18: Consider simplifying the onChange handler.

The inline arrow function can be replaced with a direct reference to props.onChange since it just passes the argument through without transformation.

♻️ Suggested simplification
-				onChange={ icon => {
-					props.onChange( icon )
-				} }
+				onChange={ props.onChange }

Comment on lines +286 to +298
public function sanitize_svg_setting( $input ) {
if ( empty( $input ) ) {
return '';
}

// Remove scripts, event handlers, foreignObject, iframe, embeds
$input = preg_replace( '/<\s*(script|iframe|embed|object|foreignObject)[^>]*>.*?<\s*\/\s*\1\s*>/is', '', $input );
$input = preg_replace( '/on\w+\s*=\s*"[^"]*"/i', '', $input );
$input = preg_replace( "/on\w+\s*=\s*'[^']*'/i", '', $input );
$input = preg_replace( '/javascript:/i', '', $input );

return $input;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

SVG sanitization may be incomplete for security-critical use.

The current implementation provides basic protection but has gaps that could allow XSS:

  1. Unquoted event handlers: The regex only handles quoted attributes (on\w+=\s*"..." and '...'), missing unquoted values like onclick=alert(1).

  2. Missing dangerous patterns:

    • data: URLs (e.g., xlink:href="data:text/html,<script>...")
    • xlink:href and href attributes pointing to javascript:
    • <use> elements referencing external content
    • <animate>, <set> elements that can trigger scripts
  3. Error handling: preg_replace returns null on error; this should be handled.

Proposed improvements for more robust sanitization
 public function sanitize_svg_setting( $input ) {
 	if ( empty( $input ) ) {
 		return '';
 	}

 	// Remove scripts, event handlers, foreignObject, iframe, embeds
 	$input = preg_replace( '/<\s*(script|iframe|embed|object|foreignObject)[^>]*>.*?<\s*\/\s*\1\s*>/is', '', $input );
+	// Remove potentially dangerous elements
+	$input = preg_replace( '/<\s*(use|animate|set|animateTransform)[^>]*\/?>/is', '', $input );
 	$input = preg_replace( '/on\w+\s*=\s*"[^"]*"/i', '', $input );
 	$input = preg_replace( "/on\w+\s*=\s*'[^']*'/i", '', $input );
+	// Handle unquoted event handlers
+	$input = preg_replace( '/on\w+\s*=\s*[^\s>]+/i', '', $input );
 	$input = preg_replace( '/javascript:/i', '', $input );
+	// Remove data: URLs and xlink:href with dangerous protocols
+	$input = preg_replace( '/xlink:href\s*=\s*["\'][^"\']*(?:javascript:|data:)[^"\']*["\']/i', '', $input );
+	$input = preg_replace( '/href\s*=\s*["\'][^"\']*(?:javascript:|data:)[^"\']*["\']/i', '', $input );

+	// Handle preg_replace errors
+	if ( $input === null ) {
+		return '';
+	}
+
 	return $input;
 }

Alternatively, consider using WordPress's built-in wp_kses with an SVG-specific allowed tags/attributes list, or a dedicated SVG sanitization library for more comprehensive protection.

🤖 Prompt for AI Agents
In `@src/editor-settings.php` around lines 286 - 298, sanitize_svg_setting
currently uses brittle regexes that miss unquoted event handlers, data: URLs,
xlink/href javascript targets, <use> references and animation elements, and does
not handle preg_replace returning null; update it to perform robust sanitization
by either (A) replacing the ad-hoc regex approach in sanitize_svg_setting with
WordPress's wp_kses using a restrictive SVG-specific allowed tags/attributes
whitelist (including removal of on* attributes regardless of quoting, stripping
href/xlink:href values that start with javascript: or data:, and disallowing
<use>, <animate>, <set>), or (B) if you keep regexes, add patterns to remove
unquoted on* attributes, strip any href/xlink:href attributes whose values begin
with javascript: or data:, remove <use>, <animate>, <set> elements, and after
each preg_replace check for null and handle by returning an empty string or
logging and returning safe output; make these changes inside the
sanitize_svg_setting function to ensure all dangerous patterns are covered.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add setting for default icon for icon list block Add settings for Heading default follow theme margins

2 participants