V4 to V5 broken command plugin

I wrote this simple plugin to run a bunch of commands. It all worked fine in v4 manifest but when I changed over to v5 it will load but none of the commands will run. Any help would be very appreciated

{
    "id": "com.uxp.layer-functions ",
    "name": "Layer Functions",
    "version": "1.0.0",
    "main": "index.js",
    "manifestVersion": 5,
    "host": [
        {
            "app": "PS",
            "minVersion": "22.4.0",
            "data": {
                "apiVersion": 2
            }
        }
    ],
    "requiredPermissions": {
        "localFileSystem": "fullAccess"
    },
 "entrypoints": [
        {
          "type": "command",
          "id": "lyrNme_BM",
          "label": {
            "default": "Rename layers: Opacity-BlendMode"
          }
        },
        {
          "type": "command",
          "id": "blendmodeFill",
          "label": {
            "default": "Fill Layer with Neutral Colour"
          }
        },
        {
          "type": "command",
          "id": "lyrVersion",
          "label": {
            "default": "Duplicate layer with timestamp"
          }
        },
        {
          "type": "command",
          "id": "duplicatetoAll",
          "label": {
            "default": "Duplicate Layers to all Documents"
          }
        }
      ],
      "icons": [
        {
          "width": 48,
          "height": 48,
          "path": "icons/light.png",
          "scale": [
            1,
            2
          ],
          "theme": [
            "darkest",
            "dark",
            "medium"
          ],
          "species": [
            "pluginList"
          ]
        },
        {
          "width": 48,
          "height": 48,
          "path": "icons/dark.png",
          "scale": [
            1,
            2
          ],
          "theme": [
            "lightest",
            "light"
          ],
          "species": [
            "pluginList"
          ]
        }
      ]
    }

Here is the Index.js


  const { entrypoints } = require("uxp");
  const { showAlert, lyrNme_BM, blendmodeFill, duplicatetoAll, lyrVersion} = require ("/lib.js");
// Set up entry points -- this defines the handler for menu items
// If this plugin had a panel, we would define flyout menu items here
entrypoints.setup({
  commands: {
    lyrNme_BM: () => lyrNme_BM(),
    blendmodeFill: () => blendmodeFill(),
    duplicatetoAll: () => duplicatetoAll(),
    lyrVersion: () => lyrVersion()
    // if we had other menu items, they would go here and in the manifest.json file.
  }
});

I’m guessing it’s something to do with the entry points setup that im missing for v5 manifest.

Since v5 if you’re changing the state of PS then you need to wrap your code in an executeAsModal call.

Manifest v5 is supported only from Ps v23.3, so you need to update that, but I doubt it’s entrypoints issue. You’re probably not using executeAsModal in your functions

1 Like

Think you both could be right @Timothy_Bennett and @Karmalakas.


const app = require("photoshop").app;
const batchPlay = require("photoshop").action.batchPlay;
const executeAsModal = ps.core.executeAsModal;

//const doc = app.activeDocument;
//const docs = app.documents
//const activeLyrs = doc.activeLayers

require("photoshop").app.Layer.prototype.colour = async (color) => {
   
return result = await batchPlay(
[
  {
     _obj: "set",
     _target: [
        {
           _ref: "layer",
           _enum: "ordinal",
           _value: "targetEnum"
        }
     ],
     to: {
        _obj: "layer",
        color: {
           _enum: "color",
           _value: color
        }
     },
     _options: {
        dialogOptions: "dontDisplay"
     }
  }
],{
  synchronousExecution: false,
  modalBehavior: "fail"
});
 
}

require("photoshop").app.Layer.prototype.ungroupLayers = async () => {


  return result = await batchPlay(
  [
     {
        _obj: "ungroupLayersEvent",
        _target: [
           {
              _ref: "layer",
              _enum: "ordinal",
              _value: "targetEnum"
           }
        ],
        _options: {
           dialogOptions: "dontDisplay"
        }
     }
  ],{
     synchronousExecution: false,
     modalBehavior: "fail"
  });
  
}

require("photoshop").app.Layer.prototype.deselectLayers = async () => {

  return result = await batchPlay(
      [
         {
            _obj: "selectNoLayers",
            _target: [
               {
                  _ref: "layer",
                  _enum: "ordinal",
                  _value: "targetEnum"
               }
            ],
            _options: {
               dialogOptions: "dontDisplay"
            }
         }
      ],{
         synchronousExecution: false,
         modalBehavior: "fail"
      });
  }


//Commands

  
async function blendmodeFill () {
   let doc = app.activeDocument;
   let docs = app.documents
   let activeLyrs = doc.activeLayers
  blendModeCheck(activeLyrs[0])
fillGray(gray)

}



async function duplicatetoAll () {
   let doc = app.activeDocument;
   let docs = app.documents


  if (docs.length > 0){

    doc.createLayerGroup({ name: "group", fromLayers: doc.activeLayers })
    for( let i = 0; i < docs.length; i++){
    if(doc != docs[i]){
    let curLayer = doc.activeLayers
    let otherdoc = docs[i]
     doc.duplicateLayers(curLayer, otherdoc)
    app.activeDocument.activeLayers[0].ungroupLayers()
    app.activeDocument.activeLayers[0].deselectLayers()
     app.activeDocument = otherdoc
     app.activeDocument.activeLayers[0].ungroupLayers()
     app.activeDocument.activeLayers[0].deselectLayers()}}
     app.activeDocument.activeLayers = null
     app.activeDocument = doc
     app.showAlert('"Duplicate to All" complete')
    }}

async function lyrNme_BM() {
      let doc = app.activeDocument;
      let docs = app.documents
      let activeLyrs = doc.activeLayers
   
       for(let i =0;i<activeLyrs.length;i++){
      
       blendModeCheck(activeLyrs[i])
       let layerOp  = Math.floor(activeLyrs[i].opacity);
   activeLyrs[i].name = blendNme + "_" + layerOp + "%"
       //  blendModeName(activeLyrs[i])
       }
     }
  
async function lyrVersion () {
    tmeStamp()
    let doc = app.activeDocument;
    let currentLayer =doc.activeLayers[0];
    let layerNme = currentLayer.name;
    let newNme = layerNme + " " + timeStamp ;
    currentLayer.colour("red")
    let dupLyr = await currentLayer.duplicate()
    dupLyr.name = newNme
    dupLyr.colour("blue")
    currentLayer.visible = false
    doc.activeLayers[0] = dupLyr
    
}


//functions 

  async function showAlert(message) {
    const app = require('photoshop').app;
    await app.showAlert(message);
  }

async function blendModeCheck(currentLayer){
    if(currentLayer.blendMode != "normal"){ 
  switch(currentLayer.blendMode){
  case "multiply":
  case "colorBurn":
  case "linearBurn":
  case "darkerCOLOR":
  blendNme = "_M"
  gray = "white"
  break;
  case "screen":
  case "lighten":
  case "colorDodge":
  case "linearDodge":
  case "lighterColor":
  blendNme = "_S"
  gray = "black"
  break;
  case "overlay":
  case "softLight":
  case "hardLight":
  case "vividLight":
  case "linearLight":
  case "pinLight":
  case "hardMix":
  blendNme = "_O"
  gray = "gray"
  break;
  case "color":
  blendNme = "_C"
  break;
  case "hue":
  blendNme = "_H"
  break;
  case "luminosity":
  blendNme = "_L"
  break;
  case "saturation":
  blendNme = "_SAT"
  break;
  case "difference":
  case "divide":
  case "subtract":
  case "exclusion":
  blendNme = "_D"
  break;}
  }
  return(blendNme, gray)
  }

async function fillGray(gray){

const result = await batchPlay(
  [
     {
        _obj: "fill",
        using: {
           _enum: "fillContents",
           _value: gray
        },
        opacity: {
           _unit: "percentUnit",
           _value: 100
        },
        mode: {
           _enum: "blendMode",
           _value: "normal"
        },
        _options: {
           dialogOptions: "dontDisplay"
        }
     }
  ],{
     synchronousExecution: false,
     modalBehavior: "fail"
  });}

  async function tmeStamp(){
   let currentTime = new Date();
   let timeOfDay;
   let month = currentTime.getMonth() + 1;
   let day = currentTime.getDate();
   let year = currentTime.getFullYear();
   let hours = currentTime.getHours();
   let minutes = currentTime.getMinutes();
   
   //fixes issues where if its 01 minute would show up as 1:1 PM for example
   if (minutes < 10) {
          minutes = "0" + minutes;
   }
   
   //Determine the time of day
   //if (hours<11) {
        //  timeOfDay = "AM";
   //}
  // else {
        //  timeOfDay = "PM";
  // }

  //Make timestamp
    timeStamp = year + "-" + month + "-"  + day + " " + hours + ":" + minutes ;
    dateStamp = year + "-" + month + "-"  + day;
   return (timeStamp, dateStamp);
}


module.exports.blendmodeFill = blendmodeFill;
module.exports.duplicatetoAll = duplicatetoAll;
module.exports.lyrNme_BM = lyrNme_BM;
module.exports.lyrVersion = lyrVersion;
module.exports.showAlert = showAlert;

  

These are my functions, what is the simplest way of wraping these in executeAsModal (I’ve made a const at the top. Many thanks for your help

The docs linked above explain it perfectly well enough and there are umpteen threads about it on the forum, for example this one.

Many thanks ill take a look

Yep wrapping relevant functions in modal sorted it all out, Many thanks @Timothy_Bennett and @Karmalakas see updated code


const app = require("photoshop").app;
const batchPlay = require("photoshop").action.batchPlay;
const {executeAsModal} = require("photoshop").core;

//const doc = app.activeDocument;
//const docs = app.documents
//const activeLyrs = doc.activeLayers

require("photoshop").app.Layer.prototype.colour = async (color) => {
   await executeAsModal(async() => {
   return result = await batchPlay(
   [
     {
        _obj: "set",
        _target: [
           {
              _ref: "layer",
              _enum: "ordinal",
              _value: "targetEnum"
           }
        ],
        to: {
           _obj: "layer",
           color: {
              _enum: "color",
              _value: color
           }
        },
        _options: {
           dialogOptions: "dontDisplay"
        }
     }
   ],{
 
   });
})
   }

require("photoshop").app.Layer.prototype.ungroupLayers = async () => {
   await executeAsModal(async() => {

   return result = await batchPlay(
   [
      {
         _obj: "ungroupLayersEvent",
         _target: [
            {
               _ref: "layer",
               _enum: "ordinal",
               _value: "targetEnum"
            }
         ],
         _options: {
            dialogOptions: "dontDisplay"
         }
      }
   ],{

   });
})
 }

require("photoshop").app.Layer.prototype.deselectLayers = async () => {
   await executeAsModal(async() => {
   return result = await batchPlay(
       [
          {
             _obj: "selectNoLayers",
             _target: [
                {
                   _ref: "layer",
                   _enum: "ordinal",
                   _value: "targetEnum"
                }
             ],
             _options: {
                dialogOptions: "dontDisplay"
             }
          }
       ],{
   
       });
      })
   }


//Commands

  
async function blendmodeFill () {
   let doc = app.activeDocument;
   let docs = app.documents
   let activeLyrs = doc.activeLayers
  blendModeCheck(activeLyrs[0])
fillGray(gray)

}



async function duplicatetoAll () {
   let doc = app.activeDocument;
   let docs = app.documents


  if (docs.length > 0){

    doc.createLayerGroup({ name: "group", fromLayers: doc.activeLayers })
    for( let i = 0; i < docs.length; i++){
    if(doc != docs[i]){
    let curLayer = doc.activeLayers
    let otherdoc = docs[i]
     doc.duplicateLayers(curLayer, otherdoc)
    app.activeDocument.activeLayers[0].ungroupLayers()
    app.activeDocument.activeLayers[0].deselectLayers()
     app.activeDocument = otherdoc
     app.activeDocument.activeLayers[0].ungroupLayers()
     app.activeDocument.activeLayers[0].deselectLayers()}}
     app.activeDocument.activeLayers = null
     app.activeDocument = doc
     app.showAlert('"Duplicate to All" complete')
    }}

async function lyrNme_BM() {
      let doc = app.activeDocument;
      let docs = app.documents
      let activeLyrs = doc.activeLayers
   
       for(let i =0;i<activeLyrs.length;i++){
      
       blendModeCheck(activeLyrs[i])
       let layerOp  = Math.floor(activeLyrs[i].opacity);
   activeLyrs[i].name = blendNme + "_" + layerOp + "%"
       //  blendModeName(activeLyrs[i])
       }
     }
  
async function lyrVersion () {
    tmeStamp()
    let doc = app.activeDocument;
    let currentLayer =doc.activeLayers[0];
    let layerNme = currentLayer.name;
    let newNme = layerNme + " " + timeStamp ;
    currentLayer.colour("red")
    let dupLyr = await currentLayer.duplicate()
    dupLyr.name = newNme
    dupLyr.colour("blue")
    currentLayer.visible = false
    doc.activeLayers[0] = dupLyr
    
}


//functions 

  async function showAlert(message) {
    const app = require('photoshop').app;
    await app.showAlert(message);
  }
//non modal
async function blendModeCheck(currentLayer){
    if(currentLayer.blendMode != "normal"){ 
  switch(currentLayer.blendMode){
  case "multiply":
  case "colorBurn":
  case "linearBurn":
  case "darkerCOLOR":
  blendNme = "_M"
  gray = "white"
  break;
  case "screen":
  case "lighten":
  case "colorDodge":
  case "linearDodge":
  case "lighterColor":
  blendNme = "_S"
  gray = "black"
  break;
  case "overlay":
  case "softLight":
  case "hardLight":
  case "vividLight":
  case "linearLight":
  case "pinLight":
  case "hardMix":
  blendNme = "_O"
  gray = "gray"
  break;
  case "color":
  blendNme = "_C"
  break;
  case "hue":
  blendNme = "_H"
  break;
  case "luminosity":
  blendNme = "_L"
  break;
  case "saturation":
  blendNme = "_SAT"
  break;
  case "difference":
  case "divide":
  case "subtract":
  case "exclusion":
  blendNme = "_D"
  break;}
  }
  return(blendNme, gray)
  }
//Modal
async function fillGray(gray){
   await executeAsModal(async() => {
   const result = await batchPlay(
     [
        {
           _obj: "fill",
           using: {
              _enum: "fillContents",
              _value: gray
           },
           opacity: {
              _unit: "percentUnit",
              _value: 100
           },
           mode: {
              _enum: "blendMode",
              _value: "normal"
           },
           _options: {
              dialogOptions: "dontDisplay"
           }
        }
     ],{
     });
   })
}
//non modal
  async function tmeStamp(){
   let currentTime = new Date();
   let timeOfDay;
   let month = currentTime.getMonth() + 1;
   let day = currentTime.getDate();
   let year = currentTime.getFullYear();
   let hours = currentTime.getHours();
   let minutes = currentTime.getMinutes();
   
   //fixes issues where if its 01 minute would show up as 1:1 PM for example
   if (minutes < 10) {
          minutes = "0" + minutes;
   }
   
   //Determine the time of day
   //if (hours<11) {
        //  timeOfDay = "AM";
   //}
  // else {
        //  timeOfDay = "PM";
  // }

  //Make timestamp
    timeStamp = year + "-" + month + "-"  + day + " " + hours + ":" + minutes ;
    dateStamp = year + "-" + month + "-"  + day;
   return (timeStamp, dateStamp);
}


module.exports.blendmodeFill = blendmodeFill;
module.exports.duplicatetoAll = duplicatetoAll;
module.exports.lyrNme_BM = lyrNme_BM;
module.exports.lyrVersion = lyrVersion;
module.exports.showAlert = showAlert;

  
1 Like

Great stuff!

Just a side note: require("photoshop").app.Layer.prototype.colour
You have already imported app at the top of your file so you don’t need to import it again, just use
app.Layer.prototype.colour

brilliant, thanks for the tip, will do