Copy link to clipboard
Copied
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?
Copy link to clipboard
Copied
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"));
}
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
thats annoying as its inconsisant with my findings
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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...
Copy link to clipboard
Copied
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);
}
 
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);
 
Let me know if this works or if I misunderstood you?