jvmtech/selective-mixins

Selective mixins for Neos CMS

Installs: 4 599

Dependents: 0

Suggesters: 0

Security: 0

Stars: 3

Watchers: 1

Forks: 1

Open Issues: 0

Type:neos-package

v3.0.0 2025-06-11 09:26 UTC

This package is auto-updated.

Last update: 2025-06-11 09:27:04 UTC


README

Latest Stable Version License

Create granular, reusable NodeTypes with ease. Best use with Props.Mixins per presentational components.

  • Load mixins multiple times in the same NodeType

    You've ever overwritten properties by choosing a not unique property name? Use our namespaces and ane the properties like what they are.

  • Choose properties you'd like to load

    You don't need a property? So don't include, not just hide it.

  • Extend labels of props and groups recursively

    You don't have to repeat the properties label text ever and ever again. Extend it.

  • Merge groups to match editor needs

    Combine multiple props of multiple mixins for a new purpose? Do it.

# YOU WRITE..

'Vendor:Teaser':
  superTypes:
    'Neos.Neos:Content': true
  options:
    superTypes:
      'Vendor:Props.Link':
        link: true
      'Vendor:Props.Headline':
        headline: true
      'Vendor:Props.Image':
        desktop: true
        mobile: true
    mergeGroups:
      images:
        'Vendor:Props.Image':
          desktop: true
          mobile: true
  ui:
    label: 'Teaser'
    inspector:
      groups:
        images:
          label: 'Images'

# YOU GET..

'Vendor:Teaser':
  superTypes:
    'Neos.Neos:Content': true
  properties:
    linkHref:
      # ...
      ui:
        inspector:
          group: linkLink
    headlineText:
      # ...
    headlineTagName:
      # ...
      ui:
        inspector:
          group: headlineHeadline
    desktopAsset:
      # ...
      ui:
        inspector:
          group: images
    mobileAsset:
      # ...
      ui:
        inspector:
          group: images
  ui:
    label: 'Teaser'
    inspector:
      groups:
        linkLink:
          label: 'Link'
        headlineHeadline:
          label: 'Headline'
        images:
          label: 'Images'

Schema

# Native usage:
{Vendor:NodeType}:
  superTypes:
    {NodeTypeNameToMixinAsItIs}: true

# Usage with namespaced mixins:
{Vendor:NodeType}:
  options:
    superTypes:
      {NodeTypeNameToCopyFrom}:
        {NamespaceToPasteInto}: true
        {AnotherNamespaceToPasteInto}: true

# Usage with namespaced and selective mixins:
{Vendor:NodeType}:
  options:
    superTypes:
      {NodeTypeNameToCopyFrom}:
        {NamespaceToPasteInto}:
          {PropertyNameToConsider}: true

# Prefix and suffix group label of all namespaced properties:
{Vendor:NodeType}:
  options:
    superTypes:
      {NodeTypeNameToCopyFrom}:
        {NamespaceToPasteInto}: 'Group Prefix %s Suffix'

# Prefix and suffix all property inspector labels:
{Vendor:NodeType}:
  options:
    superTypes:
      {NodeTypeNameToCopyFrom}:
        {NamespaceToPasteInto}:
          '*': 'Label Prefix %s Suffix'

# Override the properties inspector label:
{Vendor:NodeType}:
  options:
    superTypes:
      {NodeTypeNameToCopyFrom}:
        {NamespaceToPasteInto}:
          {PropertyNameToConsider}: 'New Property Label'
          {PropertyNameToConsider}: 'Property Prefix %s Label'

# Merge Inspector Groups:
{Vendor:NodeType}:
  ui:
    inspector:
      groups:
        newGroup:
          label: 'A new Group'
  options:
    mergeGroups:
      {NewGroupName}:
        {NamespaceToInclude}: true
        {AnotherNamespaceToInclude}: true
      {NewGroupName}:
        {Namespace}:
          {GroupNameToInclude}: true
        {AnotherNamespace}:
          {GroupName}:
            {PropertyNameToInclude}: true

Example A

Create a presentational frontend component:

prototype(Vendor:Component.Link) < prototype(Neos.Fusion:Component) {
  text = ''
  link = ''
  
  renderer = afx`
    <a href={props.link}>{props.text}</div>
  `
}

Create a corresponding reusable Props Mixin which reflects the needed Props:

'Vendor:Props.Link':
  abstract: true
  superTypes:
    'JvMTECH.SelectiveMixins:Props': true
  ui:
    inspector:
      groups:
        link:
          icon: link
          label: 'Link'
  properties:
    text:
      options:
        preset: 'rte.plaintext'
    link:
      options:
        preset: 'link.default'
      ui:
        inspector:
          group: link

And create a matching Props Fusion to load the component specific data:

prototype(Vendor:Props.Link) < prototype(JvMTECH.SelectiveMixins:Props) {
  text = JvMTECH.SelectiveMixins:Data.PlainProperty.Text {
    property = 'text'
  }
  link = JvMTECH.SelectiveMixins:Data.PlainProperty.Link {
    property = 'link'
  }
}

Now create a Content NodeType where you reuse this Props-Mixin and -Fusion as often as you like - with different namespaces:

'Vendor:Content.ThreeLinks':
  superTypes:
    'Neos.Neos:Content': true
  options:
    superTypes:
      'Vendor:Props.Link':
        left: 'Left %s'
        right: 'Right %s'
        bottom:
          link: true
  ui:
    label: 'Three Links'
    inspector:
      groups:
        bottomLink:
          label: 'Bottom Link'
prototype(Vendor:Content.ThreeLinks) < prototype(Neos.Neos:ContentComponent) {
  left = Vendor:Props.Link {
    namespace = 'left'
    // result: {
    //   text: ...
    //   link: ...
    // }
  }
  right = Vendor:Props.Link {
    namespace = 'right'
    // result: {
    //   text: ...
    //   link: ...
    // }
  }
  bottom = Vendor:Props.Link {
    namespace = 'bottom'
    // result: {
    //   link: ...
    // }
  }

  renderer = afx`
    <div class="left-col">
      <Vendor:Component.Button {...props.left} />
    </div>
    <div class="right-col">
      <Vendor:Component.Button {...props.right} />
    </div>
    <Vendor:Component.Button {...props.bottom} text="Static Label" />
  `
}

The generated NodeType will look like:

'Vendor:Content.ThreeLinks':
  superTypes:
    'Neos.Neos:Content': true
  ui:
    label: 'Three Links'
    inspector:
      groups:
        leftLink:
          icon: link
          label: 'Left Link'
        rightLink:
          icon: link
          label: 'Right Link'
        bottomLink:
          icon: link
          label: 'Bottom Link'
  properties:
    leftText:
      options:
        preset: 'rte.plaintext'
    leftLink:
      options:
        preset: 'link.default'
      ui:
        inspector:
          group: leftLink
    rightText:
      options:
        preset: 'rte.plaintext'
    rightLink:
      options:
        preset: 'link.default'
      ui:
        inspector:
          group: rightLink
    bottomLink:
      options:
        preset: 'link.default'
      ui:
        inspector:
          group: bottomLink

Example B

Merging Inspector Groups to recombine Props-Mixins (only works with options.superTypes):

'Vendor:Content.Teaser':
  superTypes:
    'Neos.Neos:Content': true
  options:
    superTypes:
      'JvMTECH.Components:Props.Headline':
        headline:
          text: true
          tagName: true
      'JvMTECH.Components:Props.Button':
        button:
          link: true
    mergeGroups:
      teaserGroup:
        headline: true
        button: true
  ui:
    label: 'Teaser'
    inspector:
      groups:
        teaserGroup:
          label: 'Teaser'

The generated NodeType will look like:

'Vendor:Content.Teaser':
  superTypes:
    'Neos.Neos:Content': true
  ui:
    label: 'Teaser'
    inspector:
      groups:
        teaserGroup:
          label: 'Teaser'
  properties:
    headlineText:
      options:
        preset: 'rte.headline'
      ui:
        inline:
          editorOptions:
            placeholder: 'JvMTECH.Base:Presets:rte.placeholder.short'
    headlineTagName:
      type: string
      defaultValue: 'h2'
      ui:
        label: 'SEO Tag'
        reloadIfChanged: true
        inspector:
          group: 'teaserGroup'
          editor: Neos.Neos/Inspector/Editors/SelectBoxEditor
          editorOptions:
            multiple: false
            allowEmpty: false
            values:
              h2:
                label: 'H2'
              h3:
                label: 'H3'
              h4:
                label: 'H4'
              h5:
                label: 'H5'
              p:
                label: 'p'
    link:
      options:
        preset: 'link.default'
      ui:
        inspector:
          group: 'teaserGroup'

Upgrade Instructions

Neos Compatibility

Neos Version Package Version
9.x 3.x
8.x 1.x, 2.x

2.x to 3.x

No Migrations are necessary

1.x to 2.x

Since 2.x SelectiveMixins does properly support nested props.

Example:

'Vendor:Props.TwoLinks':
  abstract: true
  superTypes:
    'JvMTECH.SelectiveMixins:Props': true
  options:
    superTypes:
      'Vendor:Props.Link':
        linkA: true
        linkB: true
prototype(Vendor:Props.TwoLinks) < prototype(JvMTECH.SelectiveMixins:Props) {
  linkA = Vendor:Props.Link {
    namespace = 'linkA'
  }
  linkB = Vendor:Props.Link {
    namespace = 'linkB'
  }
}

Therefor the fundamental prototype and mixin JvMTECH.SelectiveMixins:Data is now used for property loading only, and the new JvMTECH.SelectiveMixins:Props is there to create props.

And if you did use nested workarounds with something like SelectiveMixins.Array.toCamelCase([props.namespace, 'something']) you now probably just need 'something' or SelectiveMixins.Array.toCamelCase([nestedNamespace, 'something']).

Tests

Run the following test in your project to make sure the Selective NodeType generation is still working as expected, even after upgrades:

cp DistributionPackages/JvMTECH.SelectiveMixins/Tests/Functional/Fixtures/NodeTypes.yaml DistributionPackages/JvMTECH.SelectiveMixins/Configuration/NodeTypes.Test.yaml;
FLOW_CONTEXT=Testing ./flow flow:cache:flush;
FLOW_CONTEXT=Testing ./bin/phpunit -c ./DistributionPackages/JvMTECH.SelectiveMixins/Tests/PhpUnit/FunctionalTests.xml;
rm DistributionPackages/JvMTECH.SelectiveMixins/Configuration/NodeTypes.Test.yaml;

Installation

composer require jvmtech/selective-mixins

by jvmtech.ch