I released my first Photoshop UXP plugin last month, after about a year of
building. A few things I ran into that might save someone else time.
Opening a folder is not possible. I wanted a button that opens the export
folder in Explorer or Finder. It cannot be done. shell.openExternal does not
support the file scheme, and shell.openPath rejects any path without a file
extension — including with an empty extension listed in the manifest. Opening
the exported file works, after the user grants permission. I tested both
routes across two plugins before accepting it.
host must be an array. With host as an object the panel loads but stays
empty, with no error anywhere. Cost me an evening.
layerSectionExpanded is silently ignored when placed in the to object of
a batchPlay call rather than in the target reference chain. No warning, it just
does nothing.
Text layer creation reuses the selected text layer instead of creating a new
one. Fix: select a non-text layer before each creation call.
The plugin is a portrait retouching workflow — fourteen ordered steps plus eight
optional modules, all non-destructive. There is a free edition if anyone wants
to see how it is put together: velderflow.com
Let’s start from the beginning… Opening a folder is definitely possible. I’ve implemented this several times myself. What does your code look like exactly?
Edit: The links from your site to Adobe Exchange result in 404 errors… haven’t they been approved by Adobe yet?
So: file opens, folder does not. If you have the folder itself opening, could you share the manifest permissions and the exact call? Windows or macOS also matters here — I have only tested on Windows.
I’m not at my work computer right now, so here are just the first two things I can think of that might be causing the error…
I haven’t tested PS 27.10 yet, since we have enough work to do with 27.9.X… but I don’t think Adobe changed anything there. At least, I hope not, and I’ll test it.
Add " " to the “Extensions” section in the manifest… I think that’s more likely where the “error” lies.
And yes, you have to pay attention to the path for Mac and Windows!
Thanks Jan, that is a good catch — I tested “” (empty string), not " " (space). Subtle difference, and exactly the kind of thing UXP would care about.
I am away at the moment, but I will try it as soon as I am back at my machine and report here either way. If it works it saves me a feature I had already written off.
Good point on the paths too. I am using nativePath from the folder object, so that should handle both platforms — but I have only tested on Windows so far, so I will keep it in mind.
“” So without a space is correct… Just checked it a moment ago. Did you reload or restart the plugin again with DevTools? Changes in manifest need a restart! I dont know if you know this?
Good question Jan — I did Unload → Load in UDT, but I did not restart Photoshop itself. That may well be the difference. I will retest with “” and a full Photoshop restart when I am back at my machine, and report here.
Thanks for checking it on your side, that is useful to know.
Thanks for putting that together — much appreciated Ancelmoa.
I think we may be talking about two different things though. Your plugin opens the UXP folder picker (fs.getFolder()) and creates a subfolder to save into, which is useful, but that part already works fine on my side.
What I am after is opening the folder in Windows Explorer / macOS Finder — the equivalent of “Reveal in Finder”, so the user can see the exported file sitting there. That would be shell.openPath() or shell.openExternal(). I noticed your require(“uxp”).shell line is commented out, so I do not think that path is exercised here.
One thing in your manifest did catch my eye:
Json
“requiredPermissions”: {
“localFileSystem”: “fullAccess”,
“launchProcess”: {}
}
An empty launchProcess object rather than explicit schemes and extensions. Since the plugin never calls shell, that does not tell us much on its own — but it is a variant I had not tried. I will test it alongside the empty-string extension Jan suggested when I am back at my machine, with a full Photoshop restart this time.
Also noted that your host is an object rather than an array and the plugin loads fine. Good to know — I had assumed the array form was required.
Hi Justin, that is the missing piece, thanks — so it is not that I was doing it wrong, UXP simply cannot do it natively. Good to have that confirmed.
I will leave the hybrid route for now; native modules per platform is a lot of machinery for one convenience button, and I have no Mac to build and test the other half. For the moment I open the exported file instead and show the full path in the completion dialog, which covers the need well enough.
Noting it as an option if I ever have other reasons to go hybrid.
Thanks for the video and the code — that second argument to openPath() was new to me and I have added it. The permission dialog now explains what the plugin wants to do instead of just showing a bare path, which should mean fewer people clicking Block.
Between you and Jan the folder question is fully solved: the empty string in extensions makes openPath() accept a folder, and the second argument fills in the developer note in the permission prompt. Both are in my free edition now.
const { shell } = require("uxp");
await shell.openPath(folderPath, "MyPlugin wants to open the export folder");
Three things I had wrong:
The empty string "" in extensions is what makes it work. A folder has no extension, and without that entry UXP rejects the path with Extension “” is not accepted. I had tested " " (a space), which is not the same thing. Thanks to Jan for the working example.
schemes and extensions do not exclude each other. I assumed adding "" would break my https logo link. It does not — both work side by side.
openPath() takes a second argument: the text shown in Photoshop’s permission dialog. Without it the user gets a bare path and no explanation. Thanks to Ancelmoa for that one.
openExternal() with a file:// URL does not work — that part of my original post stands.
Also worth correcting: I wrote that host must be an array. It does not have to be; an object works fine. My empty panel had a different cause.