Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

Moving layers and folders out of a folder to the root via script

Contributor ,
Apr 07, 2025 Apr 07, 2025

I want to take a load of layers and layersets out of a folder so they're no longer nested. I'm using this

// Move art layers out of the STACK folder
for (var i = duplicatedStackFolder.artLayers.length - 1; i >= 0; i--) {
    duplicatedStackFolder.artLayers[i].move(newStackDoc, ElementPlacement.PLACEATEND);
}

// Move layer sets (subfolders) out of the STACK folder in forward order
for (var j = 0; j < duplicatedStackFolder.layerSets.length; j++) {
    duplicatedStackFolder.layerSets[0].move(newStackDoc, ElementPlacement.PLACEATEND);
}

 

My problem is some of the layersets get missed and not taken out of the folder.

If i use this instead then i get all the layersets but they end up in the wrong order.

// Move layer sets (subfolders) out of the STACK folder
for (var j = duplicatedStackFolder.layerSets.length - 1; j >= 0; j--) {
    duplicatedStackFolder.layerSets[j].move(newStackDoc, ElementPlacement.PLACEATEND);
}

 I've tried using PLACEATSTART but that doesn't seem to work

 

how can i resolve this?

TOPICS
Actions and scripting
193
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe
Community Expert ,
Apr 07, 2025 Apr 07, 2025

Have you tried deleting the parent layer group without deleting the contents (presuming that the parent group is no longer required)?

 

EDIT: Assuming that you have the target group selected:

 

if (app.activeDocument.activeLayer instanceof LayerSet) {
	function s2t(s) {
		return app.stringIDToTypeID(s);
	}
	var descriptor = new ActionDescriptor();
	var reference = new ActionReference();
	reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
	descriptor.putReference(s2t("null"), reference);
	descriptor.putBoolean(s2t("deleteContained"), false);
	executeAction(s2t("delete"), descriptor, DialogModes.NO);
}

 

Or ungrouping for the same result:

if (app.activeDocument.activeLayer.typename == "LayerSet") {
	app.runMenuItem(stringIDToTypeID("ungroupLayersEvent"));
}

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Apr 07, 2025 Apr 07, 2025

This works great thanks, didn't think about ungrouping.
I do have a stange problem though, any loose layers are made visible, any idea how i can retain visibilty?
Whats strange is when i go back in the history the layer is off but the result shows it clealy visible

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 07, 2025 Apr 07, 2025

I'm guessing that it's just a byproduct of ungrouping... If you use one of the methods outlined by @jduncan is layer visibility also affected?

 

EDIT: I just tested, and child layer visibility isn't affected when ungrouping or deleting the parent group.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Apr 08, 2025 Apr 08, 2025

Which did you test?

 

EDIT: I just tested, and child layer visibility isn't affected when ungrouping or deleting the parent group.


By @Stephen Marsh

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 08, 2025 Apr 08, 2025
quote

Which did you test?

 

By @jackdaw_1066

 

I tested both of my previous code samples, and neither affected the visibility of child layers when the parent layer was removed.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Apr 08, 2025 Apr 08, 2025

thats annoying as its inconsisant with my findings

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 08, 2025 Apr 08, 2025

There are other possible alternatives, duplicating layers to a new temp doc and back again or perhaps smart objects (untested, I'm just thinking out loud).

 

I ask again if the suggestions from @jduncan affected visibility?

 

It should also be possible to capture and restore visibility but that takes more work.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 08, 2025 Apr 08, 2025
LATEST
quote

There are other possible alternatives, duplicating layers to a new temp doc and back again

 

 

@jackdaw_1066—This is what I was referring to. It's more of a proof of concept than a serious suggestion, but if it helps you retain layer visibility...

 

/*

Verbose Ungroup.jsx
v.1.0 - 9th April 2025
Stephen Marsh
An alternative to the built-in Ungroup command in Photoshop
https://community.adobe.com/t5/photoshop-ecosystem-discussions/moving-layers-and-folders-out-of-a-folder-to-the-root-via-script/td-p/15255588

if (app.activeDocument.activeLayer.typename == "LayerSet") {
    app.runMenuItem(stringIDToTypeID("ungroupLayersEvent"));
}

*/

#target Photoshop;

if (app.activeDocument.activeLayer.typename == "LayerSet") {

    var origDoc = app.activeDocument;
    var origDocName = origDoc.name;
    selectChildren();
    dupeSelectedLayers("tempDoc");
    var tempDoc = app.activeDocument;
    app.activeDocument = origDoc;
    selectParent();
    deleteLayerSet(true);
    app.activeDocument = tempDoc;
    dupeSelectedLayersToOrigDoc(origDocName);
    tempDoc.close(SaveOptions.DONOTSAVECHANGES);

}


///// Functions /////

function selectChildren() {

    /*
    https://raw.githubusercontent.com/joonaspaakko/Photoshop-layer-selection-scripts/refs/heads/main/advanced/Select%20Children.jsx
    // Select Children.jsx
    // v.1.0.
    // • Selects child layers.
    // • You can select children of multiple groups at the same time.
    // • All non-group layers inside the active selection are discarded.
    */

    var doc = app.activeDocument;
    var selectedLayers = getSelectedLayers();
    var noActiveLayers = selectedLayers.id.length === 0;
    selectedLayers = noActiveLayers ? false : selectedLayers.obj;
    var ids = [];

    if (selectedLayers !== false) {
        for (var sl = 0; sl < selectedLayers.length; sl++) {

            var group = selectedLayers[sl];
            var children = group.layers;
            if (children.length) {

                for (var i = 0; i < children.length; i++) {
                    var layer = children[i];
                    var id = layer.id;
                    ids.push(id);
                }

                buildSelectionWithIDs(ids);

            }

        }
    }

    // FUNCTION WASTELAND
    // ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

    function buildSelectionWithIDs(ids) {
        for (var i = 0; i < ids.length; i++) {
            selectLayerByID(ids[i], (i === 0) ? false : "add");
        }
    }

    function selectLayerByID(id, action) {
        function cTID(s) { return app.charIDToTypeID(s); };
        function sTID(s) { return app.stringIDToTypeID(s); };
        var ref = new ActionReference();
        ref.putIdentifier(cTID('Lyr '), id);
        var desc = new ActionDescriptor();
        desc.putReference(cTID('null'), ref);
        if (action) {
            desc.putEnumerated(
                sTID('selectionModifier'),
                sTID('selectionModifierType'),
                (action === 'remove' ? sTID('removeFromSelection') : sTID('addToSelection'))
            );
        }
        desc.putBoolean(cTID('MkVs'), false);
        executeAction(cTID('slct'), desc, DialogModes.NO);
    }

    function getSelectedLayers() {
        function cTID(s) { return app.charIDToTypeID(s); };
        function sTID(s) { return app.stringIDToTypeID(s); };
        var ids = [];
        var objs = [];
        var ref = new ActionReference();
        ref.putEnumerated(cTID('Dcmn'), cTID('Ordn'), cTID('Trgt'));
        var desc = executeActionGet(ref);
        if (desc.hasKey(sTID('targetLayers'))) {
            desc = desc.getList(sTID('targetLayers'));
            var c = desc.count;
            for (var i = 0; i < c; i++) {
                var n = 0;
                try { activeDocument.backgroundLayer; } catch (e) { n = 1; }
                var idx = desc.getReference(i).getIndex() + n;
                toIdRef = new ActionReference();
                toIdRef.putProperty(cTID("Prpr"), cTID("LyrI"));
                toIdRef.putIndex(cTID("Lyr "), idx);
                var id = executeActionGet(toIdRef).getInteger(sTID("layerID"));
                selectLayerByID(id);
                if (app.activeDocument.activeLayer.typename === "LayerSet") {
                    ids.push(id);
                    objs.push(app.activeDocument.activeLayer);
                }
            }
        }
        return { id: ids, obj: objs };
    }
}

function dupeSelectedLayers(docName) {
    var s2t = function (s) {
        return app.stringIDToTypeID(s);
    };
    var descriptor = new ActionDescriptor();
    var reference = new ActionReference();
    var reference2 = new ActionReference();
    reference.putClass(s2t("document"));
    descriptor.putReference(s2t("null"), reference);
    descriptor.putString(s2t("name"), docName);
    reference2.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
    descriptor.putReference(s2t("using"), reference2);
    executeAction(s2t("make"), descriptor, DialogModes.NO);
}

function selectParent() {

    /*
    https://raw.githubusercontent.com/joonaspaakko/Photoshop-layer-selection-scripts/refs/heads/main/advanced/Select%20Parent.jsx
    // Select Parent.jsx
    // v.1.0.
    // • Selects parent layer(s)
    // • Works with a selection with multiple layers.
    // • The layers in the selection can also be in separate groups.
    // This script may be a overkill for most things. The reason it's such a
    // bulky thing is that I wanted to make it so you can select multiple parents.
    // If you just want to select a single parent, you could use the code below ↓
    // That said, this script works just fine even for selecting one parent.
    /*
  
  var doc = app.activeDocument;
  if ( doc.activeLayer.parent !== doc ) doc.activeLayer = doc.activeLayer.parent;
  */

    var selectedLayers = getSelectedLayers();
    var parentIDs = [];

    // Get parents
    for (var i = 0; i < selectedLayers.obj.length; i++) {

        var layer = selectedLayers.obj[i];
        var parentID = layer.parent.id;
        if (parentID !== false) {
            if (!parentExists(parentIDs, parentID)) parentIDs.push(parentID);
        }

    }

    buildSelectionWithIDs(parentIDs);

    // FUNCTION WASTELAND
    // ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

    function parentExists(parents, parent) {
        var inArray = false;
        for (var i = 0; i < parents.length; i++) {
            if (parents[i] == parent) {
                inArray = true;
                break;
            }
        }
        return inArray;
    }

    function buildSelectionWithIDs(ids) {
        for (var i = 0; i < ids.length; i++) {
            selectLayerByID(ids[i], (i === 0) ? false : "add");
        }
    }

    function selectLayerByID(id, action) {
        function cTID(s) { return app.charIDToTypeID(s); };
        function sTID(s) { return app.stringIDToTypeID(s); };
        var ref = new ActionReference();
        ref.putIdentifier(cTID('Lyr '), id);
        var desc = new ActionDescriptor();
        desc.putReference(cTID('null'), ref);
        if (action) {
            desc.putEnumerated(
                sTID('selectionModifier'),
                sTID('selectionModifierType'),
                (action === 'remove' ? sTID('removeFromSelection') : sTID('addToSelection'))
            );
        }
        desc.putBoolean(cTID('MkVs'), false);
        executeAction(cTID('slct'), desc, DialogModes.NO);
    }

    function getSelectedLayers() {
        function cTID(s) { return app.charIDToTypeID(s); };
        function sTID(s) { return app.stringIDToTypeID(s); };
        var ids = [];
        var objs = [];
        var ref = new ActionReference();
        ref.putEnumerated(cTID('Dcmn'), cTID('Ordn'), cTID('Trgt'));
        var desc = executeActionGet(ref);
        if (desc.hasKey(sTID('targetLayers'))) {
            desc = desc.getList(sTID('targetLayers'));
            var c = desc.count;
            for (var i = 0; i < c; i++) {
                var n = 0;
                try { activeDocument.backgroundLayer; } catch (e) { n = 1; }
                var idx = desc.getReference(i).getIndex() + n;
                toIdRef = new ActionReference();
                toIdRef.putProperty(cTID("Prpr"), cTID("LyrI"));
                toIdRef.putIndex(cTID("Lyr "), idx);
                var id = executeActionGet(toIdRef).getInteger(sTID("layerID"));
                ids.push(id);
                selectLayerByID(id);
                objs.push(app.activeDocument.activeLayer);
            }
        }
        return { id: ids, obj: objs };
    }

}

function deleteLayerSet(theBool) {
    if (app.activeDocument.activeLayer instanceof LayerSet) {
        function s2t(s) {
            return app.stringIDToTypeID(s);
        }
        var descriptor = new ActionDescriptor();
        var reference = new ActionReference();
        reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
        descriptor.putReference(s2t("null"), reference);
        descriptor.putBoolean(s2t("deleteContained"), theBool); // Delete contained layers
        executeAction(s2t("delete"), descriptor, DialogModes.NO);
    }
}

function dupeSelectedLayersToOrigDoc(theName) {
    var s2t = function (s) {
        return app.stringIDToTypeID(s);
    };
    var descriptor = new ActionDescriptor();
    var reference = new ActionReference();
    var reference2 = new ActionReference();
    reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
    descriptor.putReference(s2t("null"), reference);
    reference2.putName(s2t("document"), theName);
    descriptor.putReference(s2t("to"), reference2);
    executeAction(s2t("duplicate"), descriptor, DialogModes.NO);
}

 

Otherwise, you might need to reset the app's preferences.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 08, 2025 Apr 08, 2025
quote

thats annoying as its inconsisant with my findings


By @jackdaw_1066


Please post before/after screenshots of the layers panel to illustrate, just in case I'm not understanding the issue.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 08, 2025 Apr 08, 2025

So, I can confirm neither of @Stephen Marsh two methods, nor my two methods change the layer visibility (on my machine). One edge case may be that if a layer is visible but in a hidden group (so not visible on the screen) when removed from that group, the layer would become visible on the screen...

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 07, 2025 Apr 07, 2025

Do you just want the immediate items (first level) of the group layer moved out of the group? If so, you can just move each item like this...

// grab current document
doc = app.activeDocument;

// layer you want to move items out of
var nestedGroupLayer = doc.activeLayer;

// layer you want the moved items placed in reference to
var moveTargetLayer = doc.layers[0];

// iterate over all of the group layer items and move them out
for (var i = nestedGroupLayer.layers.length - 1; i >= 0; i--) {
    nestedGroupLayer.layers[i].move(moveTargetLayer, ElementPlacement.PLACEAFTER);
}

 CleanShot 2025-04-07 at 17.43.13.gif

 

Or if you want to extract all layers from all nested layer sets you can do it recursively like this...

function moveLayers(layerSet, layerRef) {
    for (var i = layerSet.layers.length - 1; i >= 0; i--) {
        if (layerSet.layers[i].typename == "LayerSet") {
            moveLayers(layerSet.layers[i], layerRef);
        } else {
            layerSet.layers[i].move(layerRef, ElementPlacement.PLACEAFTER);
        }
    }

    // remove empty layer set
    layerSet.remove();
}

// grab current document
doc = app.activeDocument;

// layer you want to move items out of
var nestedGroupLayer = doc.activeLayer;

// layer you want the moved items placed in reference to
var moveTargetLayer = doc.layers[0];

// recursively move all layers out of group layer
moveLayers(nestedGroupLayer, moveTargetLayer);

CleanShot 2025-04-07 at 18.00.36.gif

 

Let me know if this works or if I misunderstood you?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines