This plugin connected to OnDocFormSave, OnResourceDelete, OnResourceDuplicate, and OnResourceUndelete would do most of what you want (untested):
<?php
/* SetContainerStatus Plugin */
/* Connect to OnDocFormSave, OnResourceDelete, onResourceDuplicate, and OnResourceUndelete */
/* @var $modx modX */
/* @var $parent modResource */
/* @var $newParent modResource */
/* @var $doc modResource */
switch ($modx->event->name) {
case 'OnDocFormSave':
$children = $resource->getMany('Children');
if (!empty($children)) {
$resource->set('isfolder', true);
$resource->save();
}
$parent = $resource->getOne('parent');
if ($parent) {
$parent->set('isfolder', true);
$parent->save();
}
break;
case 'OnResourceDelete':
/* get parent object (if any) */
$parent = $resource->getOne('Parent');
if ($parent) {
/* check for siblings */
$children = $parent->getMany('Children');
if (empty($children)) {
$parent->set('isfolder', false);
$parent->save();
}
}
break;
case 'OnResourceUnDelete':
$parent = $resource->getOne('Parent');
if ($parent) {
if (! $parent->get('isfolder')) {
$parent->set('isfolder', true);
$parent->save();
}
}
break;
case 'OnResourceDuplicate':
$newChildren = $newResource->getMany('Children');
if (!empty($newChildren)) {
$newResource->set('isfolder', true);
$newResource->save();
}
$newParent = $newResource->getOne('Parent');
if ($newParent) {
if (! $newParent->get('isfolder')) {
$newParent->set('isfolder', true);
$newParent->save();
}
}
break;
}
Here's a snippet to set all existing resources. You could run it periodically to fix anything the plugin above misses:
<?php
/* Utility snippet to set container status for all existing resources */
$docs = $modx->getIterator('modResource');
foreach ($docs as $doc) {
$children = $doc->getMany('Children');
if ($children) {
if (! $doc->get('isfolder')) {
$doc->set('isfolder', true);
$doc->save();
}
}
}
Note that the plugin will not catch changes due to dragging things around in the tree. I think there's an event for that, but I couldn't find it.
Let me know if it works. If it does, I'll release it as an extra.