# blockenberg/2.0.7/blocks/feature-split/index.js

Blockenberg — 600+ Advanced Gutenberg Blocks &amp; AI Agent for WordPress Block Editor, version 2.0.7. 251 lines.

- Page: https://pluginprobe.com/plugins/blockenberg/2.0.7/code/blocks/feature-split/index.js
- Raw: https://pluginprobe.com/plugins/blockenberg/2.0.7/raw/blocks/feature-split/index.js
- Modified: 2026-03-06T12:32:40+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/blockenberg/2.0.7/code/blocks/feature-split/index.js#L10-L20`.

```javascript
/* ====================================================
   Feature Split Block — editor (index.js)
   Block: blockenberg/feature-split
   ==================================================== */
( function () {
    var el                 = wp.element.createElement;
    var Fragment           = wp.element.Fragment;
    var useState           = wp.element.useState;
    var RichText           = wp.blockEditor.RichText;
    var MediaUpload        = wp.blockEditor.MediaUpload;
    var MediaUploadCheck   = wp.blockEditor.MediaUploadCheck;
    var registerBlockType  = wp.blocks.registerBlockType;
    var InspectorControls  = wp.blockEditor.InspectorControls;
    var useBlockProps      = wp.blockEditor.useBlockProps;
    var PanelBody          = wp.components.PanelBody;
    var PanelColorSettings = wp.blockEditor.PanelColorSettings;
    var RangeControl       = wp.components.RangeControl;
    var SelectControl      = wp.components.SelectControl;
    var ToggleControl      = wp.components.ToggleControl;
    var TextControl        = wp.components.TextControl;
    var Button             = wp.components.Button;
    var __                 = wp.i18n.__;
    var _fspTC, _fspTV;
    function _tc() { return (_fspTC = _fspTC || window.bkbgTypographyControl); }
    function _tv() { return (_fspTV = _fspTV || window.bkbgTypoCssVars); }
    var IP = function () { return window.bkbgIconPicker; };

    function uid() { return 'f' + Math.random().toString(36).slice(2,7); }
    function move(arr, from, to) { var a=arr.slice(); a.splice(to,0,a.splice(from,1)[0]); return a; }

    function buildWrapStyle(a) {
        return Object.assign({
            '--bkbg-fsp-gap':        a.gap + 'px',
            '--bkbg-fsp-img-w':      a.imageWidth + '%',
            '--bkbg-fsp-img-radius': a.imageRadius + 'px',
            '--bkbg-fsp-btn-radius': a.btnRadius + 'px',
            '--bkbg-fsp-pt':         a.paddingTop + 'px',
            '--bkbg-fsp-pb':         a.paddingBottom + 'px',
            '--bkbg-fsp-content-max':a.contentMaxWidth + 'px',
            '--bkbg-fsp-eyebrow-bg': a.eyebrowBg,
            '--bkbg-fsp-eyebrow-clr':a.eyebrowColor,
            '--bkbg-fsp-h-color':    a.headlineColor,
            '--bkbg-fsp-body-color': a.bodyColor,
            '--bkbg-fsp-feat-color': a.featureColor,
            '--bkbg-fsp-prim-bg':    a.primaryBtnBg,
            '--bkbg-fsp-prim-color': a.primaryBtnColor,
            '--bkbg-fsp-sec-color':  a.secBtnColor,
            '--bkbg-fsp-accent':     a.accentColor,
            background:              a.sectionBg || undefined,
        },
            _tv()(a.typoEyebrow, '--bkbg-fsp-eb-'),
            _tv()(a.typoHeadline, '--bkbg-fsp-hl-'),
            _tv()(a.typoBody, '--bkbg-fsp-bd-'),
            _tv()(a.typoFeature, '--bkbg-fsp-ft-')
        );
    }

    /* ── REGISTER ── */
    registerBlockType('blockenberg/feature-split', {
        edit: function (props) {
            var a       = props.attributes;
            var setAttr = props.setAttributes;
            var features= a.features;

            var wrapCls = 'bkbg-fsp-wrap bkbg-fsp-style--' + a.style
                + (a.imagePosition === 'left' ? ' bkbg-fsp-img-left' : ' bkbg-fsp-img-right');
            var blockProps = useBlockProps({ className: wrapCls, style: buildWrapStyle(a) });

            function updateFeature(id, text) {
                setAttr({ features: features.map(function(f){ return f.id===id ? Object.assign({},f,{text:text}) : f; }) });
            }
            function updateFeatureIcon(id, icon) {
                setAttr({ features: features.map(function(f){ return f.id===id ? Object.assign({},f,{icon:icon}) : f; }) });
            }

            var inspector = el(InspectorControls, null,
                /* Style */
                el(PanelBody, { title:__('Style & Layout','blockenberg'), initialOpen:true },
                    el(SelectControl, { label:__('Visual style','blockenberg'), value:a.style, options:[
                        {label:__('Clean (white)','blockenberg'), value:'clean'},
                        {label:__('Dark','blockenberg'), value:'dark'},
                        {label:__('Soft gradient','blockenberg'), value:'gradient'},
                        {label:__('Accent bg','blockenberg'), value:'accent'},
                    ], onChange:function(v){ setAttr({style:v}); } }),
                    el(SelectControl, { label:__('Image position','blockenberg'), value:a.imagePosition, options:[
                        {label:__('Right','blockenberg'), value:'right'},
                        {label:__('Left','blockenberg'), value:'left'},
                    ], onChange:function(v){ setAttr({imagePosition:v}); } }),
                    el(SelectControl, { label:__('Vertical alignment','blockenberg'), value:a.verticalAlign, options:[
                        {label:'Center', value:'center'},{label:'Top', value:'flex-start'},{label:'Bottom', value:'flex-end'}
                    ], onChange:function(v){ setAttr({verticalAlign:v}); } }),
                    el(RangeControl, { label:__('Column gap (px)','blockenberg'), value:a.gap, min:0, max:120, onChange:function(v){ setAttr({gap:v}); } }),
                    el(RangeControl, { label:__('Image width %','blockenberg'), value:a.imageWidth, min:30, max:70, onChange:function(v){ setAttr({imageWidth:v}); } }),
                    el(RangeControl, { label:__('Image border radius (px)','blockenberg'), value:a.imageRadius, min:0, max:40, onChange:function(v){ setAttr({imageRadius:v}); } }),
                    el(ToggleControl, { label:__('Image shadow','blockenberg'), checked:a.imageShadow, onChange:function(v){ setAttr({imageShadow:v}); } })
                ),

                /* Content */
                el(PanelBody, { title:__('Content','blockenberg'), initialOpen:false },
                    el(ToggleControl, { label:__('Show eyebrow badge','blockenberg'), checked:a.showEyebrow, onChange:function(v){ setAttr({showEyebrow:v}); } }),
                    el(ToggleControl, { label:__('Show body text','blockenberg'),    checked:a.showBody,    onChange:function(v){ setAttr({showBody:v}); } }),
                    el(ToggleControl, { label:__('Show feature list','blockenberg'), checked:a.showFeatures,onChange:function(v){ setAttr({showFeatures:v}); } }),
                    el(ToggleControl, { label:__('Show primary button','blockenberg'), checked:a.showPrimaryBtn, onChange:function(v){ setAttr({showPrimaryBtn:v}); } }),
                    el(ToggleControl, { label:__('Show secondary button','blockenberg'), checked:a.showSecondaryBtn, onChange:function(v){ setAttr({showSecondaryBtn:v}); } }),
                    a.showEyebrow ? el(TextControl, { label:__('Eyebrow text','blockenberg'), value:a.eyebrow, onChange:function(v){ setAttr({eyebrow:v}); } }) : null,
                    a.showPrimaryBtn ? el(Fragment, null,
                        el(TextControl, { label:__('Primary button label','blockenberg'), value:a.primaryBtnLabel, onChange:function(v){ setAttr({primaryBtnLabel:v}); } }),
                        el(TextControl, { label:__('Primary button URL','blockenberg'), value:a.primaryBtnUrl, onChange:function(v){ setAttr({primaryBtnUrl:v}); } }),
                        el(ToggleControl, { label:__('Open in new tab','blockenberg'), checked:a.primaryBtnTarget, onChange:function(v){ setAttr({primaryBtnTarget:v}); } })
                    ) : null,
                    a.showSecondaryBtn ? el(Fragment, null,
                        el(TextControl, { label:__('Secondary button label','blockenberg'), value:a.secondaryBtnLabel, onChange:function(v){ setAttr({secondaryBtnLabel:v}); } }),
                        el(TextControl, { label:__('Secondary button URL','blockenberg'), value:a.secondaryBtnUrl, onChange:function(v){ setAttr({secondaryBtnUrl:v}); } })
                    ) : null,
                    el(RangeControl, { label:__('Content max width (px)','blockenberg'), value:a.contentMaxWidth, min:300, max:800, onChange:function(v){ setAttr({contentMaxWidth:v}); } })
                ),

                /* Feature list */
                a.showFeatures ? el(PanelBody, { title:__('Feature items','blockenberg'), initialOpen:false },
                    features.map(function(f, idx) {
                        return el('div', { key:f.id, style:{ display:'flex', gap:'4px', marginBottom:'6px', alignItems:'center' } },
                            el('div', { style:{ flexShrink:0 } },
                                el(IP().IconPickerControl, {
                                    iconType: f.iconType, customChar: f.icon, dashicon: f.iconDashicon, imageUrl: f.iconImageUrl,
                                    onChangeType: function(v){ setAttr({features:features.map(function(x){ return x.id===f.id ? Object.assign({},x,{iconType:v}) : x; })}); },
                                    onChangeChar: function(v){ updateFeatureIcon(f.id,v); },
                                    onChangeDashicon: function(v){ setAttr({features:features.map(function(x){ return x.id===f.id ? Object.assign({},x,{iconDashicon:v}) : x; })}); },
                                    onChangeImageUrl: function(v){ setAttr({features:features.map(function(x){ return x.id===f.id ? Object.assign({},x,{iconImageUrl:v}) : x; })}); }
                                })
                            ),
                            el(TextControl, { label: idx===0 ? __('Text','blockenberg') : undefined, value:f.text, onChange:function(v){ updateFeature(f.id,v); }, style:{ flex:1 } }),
                            el(Button, { icon:'arrow-up', isSmall:true, disabled:idx===0, onClick:function(){ setAttr({features:move(features,idx,idx-1)}); } }),
                            el(Button, { icon:'no-alt', isSmall:true, isDestructive:true, onClick:function(){ setAttr({features:features.filter(function(_,i){ return i!==idx; })}); } })
                        );
                    }),
                    el(Button, { variant:'secondary', isSmall:true, style:{width:'100%',marginTop:'4px'},
                        onClick:function(){ setAttr({ features: features.concat([{id:uid(),icon:'✅',text:'New feature',iconType:'custom-char',iconDashicon:'',iconImageUrl:''}]) }); }
                    }, __('+ Add feature','blockenberg'))
                ) : null,

                /* Spacing */
                el(PanelBody, { title:__('Spacing','blockenberg'), initialOpen:false },
                    el(RangeControl, { label:__('Padding top (px)','blockenberg'),    value:a.paddingTop,    min:0, max:160, onChange:function(v){ setAttr({paddingTop:v}); } }),
                    el(RangeControl, { label:__('Padding bottom (px)','blockenberg'), value:a.paddingBottom, min:0, max:160, onChange:function(v){ setAttr({paddingBottom:v}); } }),
                    el(RangeControl, { label:__('Button radius (px)','blockenberg'),  value:a.btnRadius,     min:0, max:50,  onChange:function(v){ setAttr({btnRadius:v}); } })
                ),

                /* Typography */
                el(PanelBody, { title:__('Typography','blockenberg'), initialOpen:false },
                    _tc() && el(_tc(), { label: __('Headline', 'blockenberg'), value: a.typoHeadline, onChange: function (v) { setAttr({ typoHeadline: v }); } }),
                    _tc() && el(_tc(), { label: __('Body', 'blockenberg'), value: a.typoBody, onChange: function (v) { setAttr({ typoBody: v }); } }),
                    _tc() && el(_tc(), { label: __('Feature', 'blockenberg'), value: a.typoFeature, onChange: function (v) { setAttr({ typoFeature: v }); } }),
                    _tc() && el(_tc(), { label: __('Eyebrow', 'blockenberg'), value: a.typoEyebrow, onChange: function (v) { setAttr({ typoEyebrow: v }); } })
                ),

                /* Colors */
                el(PanelColorSettings, { title:__('Colors','blockenberg'), initialOpen:false, colorSettings:[
                    {label:__('Section background','blockenberg'), value:a.sectionBg,       onChange:function(v){ setAttr({sectionBg:v||''}); }},
                    {label:__('Eyebrow bg','blockenberg'),         value:a.eyebrowBg,       onChange:function(v){ setAttr({eyebrowBg:v||''}); }},
                    {label:__('Eyebrow color','blockenberg'),      value:a.eyebrowColor,    onChange:function(v){ setAttr({eyebrowColor:v||''}); }},
                    {label:__('Headline color','blockenberg'),     value:a.headlineColor,   onChange:function(v){ setAttr({headlineColor:v||''}); }},
                    {label:__('Body text color','blockenberg'),    value:a.bodyColor,       onChange:function(v){ setAttr({bodyColor:v||''}); }},
                    {label:__('Feature text color','blockenberg'), value:a.featureColor,    onChange:function(v){ setAttr({featureColor:v||''}); }},
                    {label:__('Primary btn bg','blockenberg'),     value:a.primaryBtnBg,    onChange:function(v){ setAttr({primaryBtnBg:v||''}); }},
                    {label:__('Primary btn text','blockenberg'),   value:a.primaryBtnColor, onChange:function(v){ setAttr({primaryBtnColor:v||''}); }},
                    {label:__('Secondary btn color','blockenberg'),value:a.secBtnColor,     onChange:function(v){ setAttr({secBtnColor:v||''}); }},
                    {label:__('Accent color','blockenberg'),       value:a.accentColor,     onChange:function(v){ setAttr({accentColor:v||''}); }},
                ] })
            );

            /* Content column */
            var contentEl = el('div', {
                className: 'bkbg-fsp-content',
                style: { background: a.contentBg || undefined, alignSelf: a.verticalAlign }
            },
                a.showEyebrow ? el('span', { className:'bkbg-fsp-eyebrow' }, a.eyebrow) : null,
                el(RichText, { tagName:'h2', className:'bkbg-fsp-headline', value:a.headline, onChange:function(v){ setAttr({headline:v}); }, placeholder:__('Compelling headline…','blockenberg') }),
                a.showBody ? el(RichText, { tagName:'p', className:'bkbg-fsp-body', value:a.body, onChange:function(v){ setAttr({body:v}); }, placeholder:__('Body text…','blockenberg') }) : null,
                a.showFeatures ? el('ul', { className:'bkbg-fsp-features' },
                    features.map(function(f){
                        return el('li', { key:f.id, className:'bkbg-fsp-feature' },
                            el('span', { className:'bkbg-fsp-feature-icon' }, (f.iconType || 'custom-char') !== 'custom-char' ? IP().buildEditorIcon(f.iconType, f.icon, f.iconDashicon, f.iconImageUrl, f.iconDashiconColor) : f.icon),
                            el('span', { className:'bkbg-fsp-feature-text' }, f.text)
                        );
                    })
                ) : null,
                (a.showPrimaryBtn || a.showSecondaryBtn) ? el('div', { className:'bkbg-fsp-btns' },
                    a.showPrimaryBtn ? el('a', { className:'bkbg-fsp-btn bkbg-fsp-btn--primary', href:a.primaryBtnUrl, onClick:function(e){ e.preventDefault(); } }, a.primaryBtnLabel) : null,
                    a.showSecondaryBtn ? el('a', { className:'bkbg-fsp-btn bkbg-fsp-btn--secondary', href:a.secondaryBtnUrl, onClick:function(e){ e.preventDefault(); } }, a.secondaryBtnLabel) : null
                ) : null
            );

            /* Image column */
            var imageEl = el('div', { className:'bkbg-fsp-image-wrap' + (a.imageShadow ? ' bkbg-fsp-shadow' : '') },
                a.imageUrl
                    ? el('img', { src:a.imageUrl, alt:a.imageAlt, className:'bkbg-fsp-img' })
                    : el(MediaUploadCheck, null,
                        el(MediaUpload, {
                            onSelect:function(m){ setAttr({ imageUrl:m.url, imageId:m.id, imageAlt:m.alt||'' }); },
                            allowedTypes:['image'], value:a.imageId,
                            render:function(o){ return el(Button, { onClick:o.open, className:'bkbg-fsp-img-placeholder', variant:'secondary' }, __('+ Choose image','blockenberg')); }
                        })
                    ),
                a.imageUrl ? el('div', { className:'bkbg-fsp-img-actions' },
                    el(Button, { isSmall:true, variant:'secondary', onClick:function(){ setAttr({ imageUrl:'', imageId:0 }); } }, __('Remove','blockenberg'))
                ) : null
            );

            return el(Fragment, null,
                inspector,
                el('div', blockProps,
                    a.imagePosition === 'right' ? el(Fragment, null, contentEl, imageEl) : el(Fragment, null, imageEl, contentEl)
                )
            );
        },

        save: function (props) {
            var a = props.attributes;
            var wrapCls = 'bkbg-fsp-wrap bkbg-fsp-style--' + a.style
                + (a.imagePosition === 'left' ? ' bkbg-fsp-img-left' : ' bkbg-fsp-img-right');
            var blockProps = wp.blockEditor.useBlockProps.save({ className: wrapCls, style: buildWrapStyle(a) });

            var contentEl = el('div', { className:'bkbg-fsp-content', style:{ alignSelf:a.verticalAlign } },
                a.showEyebrow ? el('span', { className:'bkbg-fsp-eyebrow' }, a.eyebrow) : null,
                el(RichText.Content, { tagName:'h2', className:'bkbg-fsp-headline', value:a.headline }),
                a.showBody ? el(RichText.Content, { tagName:'p', className:'bkbg-fsp-body', value:a.body }) : null,
                a.showFeatures ? el('ul', { className:'bkbg-fsp-features' },
                    a.features.map(function(f){
                        return el('li', { key:f.id, className:'bkbg-fsp-feature' },
                            el('span', { className:'bkbg-fsp-feature-icon' }, (f.iconType || 'custom-char') !== 'custom-char' ? IP().buildSaveIcon(f.iconType, f.icon, f.iconDashicon, f.iconImageUrl, f.iconDashiconColor) : f.icon),
                            el('span', { className:'bkbg-fsp-feature-text' }, f.text)
                        );
                    })
                ) : null,
                (a.showPrimaryBtn || a.showSecondaryBtn) ? el('div', { className:'bkbg-fsp-btns' },
                    a.showPrimaryBtn ? el('a', { className:'bkbg-fsp-btn bkbg-fsp-btn--primary', href:a.primaryBtnUrl, target: a.primaryBtnTarget ? '_blank' : undefined }, a.primaryBtnLabel) : null,
                    a.showSecondaryBtn ? el('a', { className:'bkbg-fsp-btn bkbg-fsp-btn--secondary', href:a.secondaryBtnUrl }, a.secondaryBtnLabel) : null
                ) : null
            );

            var imageEl = el('div', { className:'bkbg-fsp-image-wrap' + (a.imageShadow ? ' bkbg-fsp-shadow' : '') },
                a.imageUrl ? el('img', { src:a.imageUrl, alt:a.imageAlt, className:'bkbg-fsp-img', loading:'lazy' }) : null
            );

            return el('div', blockProps,
                a.imagePosition === 'right' ? el(Fragment, null, contentEl, imageEl) : el(Fragment, null, imageEl, contentEl)
            );
        }
    });
}() );

```
