Get layer list from layers inside of a group?

Based on this documentation, it seems that it is only possible to get a list of top-level layers. Is there a way to get a list of layers from inside groups? It seems there must be a way I would think.

https://developer.adobe.com/photoshop/uxp/2022/ps_reference/classes/layers/

You can do it with this function (Iā€™ve added some typescript for better type checking and you can remove it if you want to):

import { app, constants } from "photoshop";
import { Layers } from "photoshop/dom/collections/Layers";
import { Layer } from "photoshop/dom/Layer";

export const getAllLayers = (
  layers: Layers = app.activeDocument.layers,
  allLayers: Layer[] = []
) => {
  layers.forEach((layer: Layer) => {
    if (layer.kind !== constants.LayerKind.GROUP) {
      allLayers.push(layer);
    } else {
      getAllLayers(layer.layers, allLayers);
    }
  });
  return allLayers;
};

and to call it you can just write it like this

const documentLayers = getAllLayers();

2 Likes

Here I made it even shorter using ternary operator :slight_smile:

import { app, constants } from "photoshop";
import { Layers } from "photoshop/dom/collections/Layers";
import { Layer } from "photoshop/dom/Layer";

export const getAllLayers = (
  layers: Layers = app.activeDocument.layers,
  allLayers: Layer[] = []
) => {
  layers.forEach((layer: Layer) =>
    layer.kind !== constants.LayerKind.GROUP
      ? allLayers.push(layer)
      : getAllLayers(layer.layers, allLayers)
  );
  return allLayers;
};

Thanks. I need to give it a try. Iā€™m not familiar with typescript. Which parts to I need to remove?

Because typescript is just a superset of javascript any javascript code is also valid typescript code. If you use Visual Studio Code and try to copy-paste this code into a .js file it will warn you with the red squiggly lines. Thatā€™s part of the code that needs to be removed :slight_smile:

So here is the result (plain javascript):

import { app, constants } from "photoshop";

export const getAllLayers = (
  layers = app.activeDocument.layers,
  allLayers = []
) => {
  layers.forEach((layer) =>
    layer.kind !== constants.LayerKind.GROUP
      ? allLayers.push(layer)
      : getAllLayers(layer.layers, allLayers)
  );
  return allLayers;
};

Over time I switched to typescript because of that type declaration and in my opinion, it keeps my code better and prevents errors.

Thanks!
I use Brackets. Iā€™m not a ā€œrealā€ programmer so I donā€™t use Visual Studio. I know just enough to hack together some javascript to make my Photoshop ideas work :slight_smile:

1 Like

Youā€™re welcome :grinning: I also used Brackets before and I love the color theme it has so when switched to VS code I found and immediately installed that same color theme.

Brackets :heart:
I built my first enterprise CEP plugin with it because the IT department wouldnā€™t let me install VS Code.
I smashed out ā‰ˆ10k lines of code in 3 months having never written a jot of JS in my life and tbh Bracketsā€™ simplicity definitely helped with that - Iā€™ll always have a soft spot for it.
That said, VS Code is flipping great and much like Photoshop it can seem really daunting at first because it is so feature rich, but when you realise that you only need about 10% of those features to actually produce working code itā€™s not so bad.
Definitely worth giving it a shot - itā€™s worth it for IntelliSense alone (the thing that reads your code as you type and autocompletes).

1 Like

Hey there, what should I do if app.activeDocument is valid and returns itā€™s name correctly, but app.activeDocument.layers is always empty?

as mentioned in other topics, layers is a proxy not an actual array.
you can loop through it like arrays just not using for-in, you can the good old for i++ or for-of

1 Like

you can use the ā€œguard clauseā€ with optional chaining (?) for that.
if (!layers) return;

complete code

import { app, constants } from "photoshop";

const getAllLayers = (
  layers = app.activeDocument?.layers,
  allLayers = []
) => {
  if (!layers) return;
  layers.forEach((layer) =>
    layer.kind !== constants.LayerKind.GROUP
      ? allLayers.push(layer)
      : getAllLayers(layer.layers, allLayers)
  );
  return allLayers;
};

the function is going to return undefined if no layers are found.

Also, if you donā€™t want to show the error to the user, but still want to log it for debugging purposes you can wrap the entire logic into try...catch block. Something like this:

try {
  // Logic goes here...
} catch (error) {
  console.log(error)
}