PHPackages                             sitegeist/criticalmass - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. sitegeist/criticalmass

Abandoned → [punktde/archivist](/?search=punktde%2Farchivist)ArchivedNeos-package[Utility &amp; Helpers](/categories/utility)

sitegeist/criticalmass
======================

Handle critical masses of nodes in Neos

v3.0.1(8y ago)94.8k1GPL-3.0PHP

Since Jun 8Pushed 8y ago3 watchersCompare

[ Source](https://github.com/sitegeist/Sitegeist.CriticalMass)[ Packagist](https://packagist.org/packages/sitegeist/criticalmass)[ RSS](/packages/sitegeist-criticalmass/feed)WikiDiscussions master Synced 2mo ago

READMEChangelog (8)Dependencies (1)Versions (15)Used By (0)

Sitegeist.CriticalMass
======================

[](#sitegeistcriticalmass)

Tools for managing large amounts of nodes
-----------------------------------------

[](#tools-for-managing-large-amounts-of-nodes)

### Automatic creation of node-hierarchies

[](#automatic-creation-of-node-hierarchies)

In Neos it is sometimes hard to handle high amounts of documents below a single parent node. In such cases it is hard for editors to find a specific document again. On top of that the performance and usability of the current navigate-component will suffer if too many nodes are on a single level.

To overcome this we suggest to use a hierarchical structure of collection-nodes to create a node structure that is appropriate for the current project and that helps editors to find documents. This solution has the additional benefit of representing that structure in the document-url aswell, that makes url-collisions much less likely.

*Since the creation of such a node hierarchy is a repetitive task we provide this package to help automating that.*

A common use case would be to automatically create NewsCollection Nodes for Year and Month and move any News Node into a matchig collection node.

### Importing of nodes from CSV-Files

[](#importing-of-nodes-from-csv-files)

It is a repeated requirement to import data from table-structures into neos that usually requires the implementation of custom import controllers. This package allows to configure the import into nodes or even into node hierarchies.

NOTE: The import works together with the automatic node-hierarchy creation. So if you want to import into a structure you can configure both options.

### Exporting of nodes to CSV-Files

[](#exporting-of-nodes-to-csv-files)

For exporting nodes into a table-structure the package allow the configuration of the expression to query for nodes and expressions for each column of the imported table.

Authors &amp; Sponsors
----------------------

[](#authors--sponsors)

- Wilhelm Behncke -
- Martin Ficzel -

*The development and the public-releases of this package is generously sponsored by our employer .*

Usage
-----

[](#usage)

```
Sitegeist:
  CriticalMass:

    #
    # Automatic hierarchy creation
    #
    automaticNodeHierarchy:

      # The configuration for the node type Sitegeist.CriticalMass:ExampleNode
      'Sitegeist.CriticalMass:ExampleNode':

        # optional: Eel-values that are evaluates first and afterwards are available in the context
        # of the eel expressions below. During evaluation the `site`, `documentNode` and `node` values are present.
        context:
          year: "${q(node).property('startDate') ? Date.year(q(node).property('startDate')) : 'no-year'}"
          month: "${q(node).property('startDate') ? Date.month(q(node).property('startDate')) : 'no-month'}"

        # Detect the root-collection node that will contain the automatically created node hierarchy
        root: "${q(node).parents().filter('[instanceof Sitegeist.CriticalMass:ExampleNodeCollection]').slice(-1, 1).get(0)}"

        # optional: Automatically publish the created document hierarchy
        autoPublishPath: true

        # optional: Decide wether a node shall be handled or not
        condition: "${q(node).property('startDate') ? true : false}"

        # optional: The sorting of the nodes inside the target hierarchy
        sortBy: '${q(a).property("title") < q(b).property("title")}'

        # Define the levels of the node hierarchy that are created beneath the root node
        path:

          # level 1 year
          -
            # the type of the hierarchy-node
            type: 'Sitegeist.CriticalMass:ExampleNodeCollection'

            # eel-expression to find existing collection nodes
            # the context contains the parent node as `parent` in addition to the default context values
            node: "${q(parent).children('[uriPathSegment = '\' + year + ' '\]').get(0)}"

            # optional: the sorting of the nodes on this level
            # the eel expression gets two nodes `a` and `b` in the context
            sortBy: '${q(a).property("title") < q(b).property("title")}'

            # properties that are applied only on node creation and can be edited afterwards
            properties:
              title: "${year}"
              uriPathSegment: "${year}"

          # level 2 month
          -
            # the type and nodename of the hierarchy-node
            type: 'Sitegeist.CriticalMass:ExampleNodeCollection'
            # eel-expression to find existing collection nodes
            # the context contains the parent node as `parent` in addition to the default context values
            node: "${q(parent).children('[uriPathSegment = '\' + month + ' '\]').get(0)}"

            # optional: the sorting of the nodes on this level
            # the eel expression gets two nodes `a` and `b` in the context
            sortBy: '${q(a).property("title") < q(b).property("title")}'

            # properties that are applied only on node creation and can be edited afterwards
            properties:
              title: "${month}"
              uriPathSegment: "${month}"

    #
    # Node-import
    #
    import:

      # A single import preset for Sitegeist.CriticalMass:ExampleNode
      #
      # !!! All expressions in here are evaluated with the `site` and the current `row` in the context.
      example-import:

        # optional: Description for the preset
        description: "Example-import description"

        # optional Eel-values that are evaluates first and afterwards are available in the context
        context:
          base: "${q(site).find('[instanceof Sitegeist.CriticalMass:ExampleCollection]').get(0)}"

        # optional: Configuration for importing previously imported nodes
        update:
          # Expression that returns the node that shall be updated
          node: "${q(base).find('[instanceof Sitegeist.CriticalMass:ExampleNode][importIdentifier=\"' +  row['ID'] + '\"]').get(0)}"

        # optional: Configuration for creating new nodes if no update was configured or no preexisting node is found
        create:
          # optional: skip import under certain conditions
          condition: "${row['ID'] ? true : false}"
          # Expression that returns the node that shall be updated
          parentNode: "${base}"
          # The type of the node that shall be created
          type: 'Sitegeist.CriticalMass:ExampleNode'
          # optional:  The properties that are set once for new imported nodes
          properties:
            'importIdentifier': "${row['ID']}"

        # The properties that are updated during import AND update
        properties:
          'title': "${row['Title']}"
          'subtitle': "${row['Subtitle']}"
          'description': "${row['Description']}"
          'date': "${Date.parse(row['Date'], 'y-m-d')}"

        # optional: Import data into descendent-nodes
        #
        # !!! The expressions in here have the imported or updated node in the context as `ancestor`
        #
        # All the configuration from the main level can be used in here aswell. Descendent-nodes can
        # even have their own descendent nodes.
        descendants:
          image:
            update:
              node: "${q(ancestor).children('images').children().get(0)}"
            create:
              condition: "${row['Image'] ? true : false}"
              parentNode: "${q(ancestor).children('images').get(0)}"
              nodeType: 'Sitegeist.CriticalMass:ExampleImage'
            properties:
              'title': "${row['Title']}"
              'image': "${row['Image']}"

    #
    # Node-export
    #
    export:

      # A single export preset for Sitegeist.CriticalMass:ExampleNode
      #
      # !!! All expressions in here are evaluated with the `site` and the current `row` in the context.
      example-export:

        # optional: Description for the preset
        description: "Example-export description"

        # Expression that returns the nodes that shall be exported
        nodes: "${q(site).find('[instanceof Sitegeist.CriticalMass:ExampleNode]').get()}"

        # The properties that are exported
        #
        # Each configuration key in here is evaluated as en expression with 'site' and 'node' in the context.
        properties:
          'ID': "${q(node).property('importIdentifier')}"
          'Title': "${q(node).property('title')}"
          'Subtitle': "${q(node).property('subtitle')}"
          'Date': "${Date.format(q(node).property('date'), 'y-m-d')}"
          'Image': "${q(node).children('images').children().first().property('image')}"
```

Commands
--------

[](#commands)

- `./flow csv:showpresets` - List the defined import and export presets
- `./flow csv:import  ` - Import or update nodes from csv-file
- `./flow csv:export  ` - Export nodes to csv-file

*The import- and export-commands are expecting the field-names in the first line of the csv-file.*

The import and export commands have an optional parameter `--site-node` that can be used to specify the site for the import. If this parameter is not given the default of the current Neos-setup is used.

Limitations
-----------

[](#limitations)

The following issues and side effects are known at the moment:

1. Currently there is no way to notify the navigate component about a needed reload. So after a node was moved behind the scene, the navigate component will keep displaying the node on the current position until the next reload.
2. The automatically created nodes are in the user workspace and still have to be published. If you want to avoid this use the option `autoPublishPath`.

Installation
------------

[](#installation)

Sitegeist.CriticalMass is available via packagist. Just add `"sitegeist/criticalmass" : "~1.0"` to the require-dev section of the composer.json or run `composer require --dev sitegeist/criticalmass`. We use semantic-versioning so every breaking change will increase the major-version number.

License
-------

[](#license)

see [LICENSE file](LICENSE)

###  Health Score

35

—

LowBetter than 79% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity24

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity71

Established project with proven stability

 Bus Factor1

Top contributor holds 88.1% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~86 days

Total

9

Last Release

2941d ago

Major Versions

1.0.x-dev → v2.0.02017-05-10

v2.3.0 → v3.0.02017-10-12

### Community

Maintainers

![](https://www.gravatar.com/avatar/51e0a02d8e12b73949ec858638aa7e295e103022cc5a879f86ac8532c2c170bd?d=identicon)[sitegeist](/maintainers/sitegeist)

![](https://www.gravatar.com/avatar/829b4ccb51e8cff3c1e4b59d60cfe8d1b86f6d77fc31a6b3fc99227f432542ca?d=identicon)[mficzel](/maintainers/mficzel)

---

Top Contributors

[![mficzel](https://avatars.githubusercontent.com/u/1309380?v=4)](https://github.com/mficzel "mficzel (118 commits)")[![grebaldi](https://avatars.githubusercontent.com/u/2522299?v=4)](https://github.com/grebaldi "grebaldi (16 commits)")

### Embed Badge

![Health badge](/badges/sitegeist-criticalmass/health.svg)

```
[![Health](https://phpackages.com/badges/sitegeist-criticalmass/health.svg)](https://phpackages.com/packages/sitegeist-criticalmass)
```

###  Alternatives

[datlechin/filament-menu-builder

Create and manage menus and menu items

13550.3k2](/packages/datlechin-filament-menu-builder)[sitegeist/silhouettes

Preconfigure property-silhuettes that can be applied to various properties of multiple NodeTypes.

16157.5k](/packages/sitegeist-silhouettes)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
