decaporg / decap-cms

A Git-based CMS for Static Site Generators
https://decapcms.org
MIT License
17.97k stars 3.05k forks source link

Update Cloudinary widget so that you can opt to inset the filepath of the image, not the filename alone #4725

Open katcoutts opened 3 years ago

katcoutts commented 3 years ago

Is your feature request related to a problem? Please describe. We are going to be integrating Cloudinary with NetlifyCMS. Ideally, when people are adding images via Cloudinary, we would like the resulting markdown to specify the filepath for the file within Cloudinary. At the moment the only options are to output the full Cloudinary URL, or the filename only. Filename only is no use to us as we have different folders so need to know the full path of the image in cloudinary.

Describe the solution you'd like You can opt, when using Cloudinary, for a "filepath only" option.

Describe alternatives you've considered Using the full url and using a preSave hook to strip out everything before the filepath within Cloudinary - but given a number of fields use the image widget and images are also put in the body of content, this doesn't actually seem like it would be very easy to do.

Additional context

tonyketcham commented 3 years ago

I'm working on a PR for this!

@katcoutts, just so we're on the same page - let's take this Cloudinary asset URL of mine as an example: https://res.cloudinary.com/pu-erh/image/upload/v1608103339/test/nestA/BUDDING_LEAVES_CROPPED_bxsny8.png

Is the path you're expecting to be output to the markdown everything after the version number v1608103339? Hence, /test/nestA/BUDDING_LEAVES_CROPPED_bxsny8.png which represents the path relative to the home directory in Cloudinary.

katcoutts commented 3 years ago

Yes @tonyketcham - that's exactly what I'm after. Fantastic. Do you have any idea on a likely timeframe?

tonyketcham commented 3 years ago

I should have a solution up by next week but I can't speak to if/when my PR would get integrated, so stay tuned

smashercosmo commented 3 years ago

This feature is also very important if you use netlifycms + next.js. Because next/image component can use cloudinary (and other image providers) to optimize images, but it only works with relative urls.

katcoutts commented 3 years ago

Happy New Year @tonyketcham . Just wondered how the PR for this was getting on?

tonyketcham commented 3 years ago

@katcoutts my apologies, been very busy and this ended up being more complex than I'd initially expected.

The solution appears to go a good bit deeper than just this widget, where the data that's returned under the hood from Cloudinary (an image asset's public_id) is actually already just what you've proposed - it gives the file path.

However, to create a case where we just return that raw public_id with the file path in it has given me some difficulty because of a core library functionality. Going back to the Cloudinary widget - the output_filename_only option is in fact already just returning that raw public_id, which doesn't get all the way to the markdown. On an image entry event, if the image's source is not an absolute path like a URL, the string is matched by a reducer in the core that trims everything off up until the file name - effectively defaulting us to either choosing between the file name or absolute path on the core level.

So, for a nested image within a Cloudinary folder which has public_id = "samples/animals/reindeer.jpg", doing something like:

switch (output_format) {
...

  case 'file_path': {
     return '//' + asset.public_id + '.' + asset.format;
  }

...
}

in the Cloudinary widget gets past that core reducer and gives us something workable but not exactly ideal:

---
title: "Cloudinary Test 2 (output_format: file_path)"
image: //samples/animals/reindeer.jpg
---

whereas anything else will give the file name:

case 'file_path': {
   return '/real/hardcoded/extra/stuff/' + asset.public_id + '.' + asset.format;
}
---
title: "Cloudinary Test 2 (output_format: file_path)"
image: /reindeer.jpg
---

So that leaves me currently figuring out how to additively work around that reducer without introducing any breaking changes since all media library widgets pass through that. The most minimally-invasive solution to this I've been considering is adding logic to the core's media file public path generator that checks if the state of the new media_library config option I added, output_format, is equal to "file_path" which would then escape the reducer and return the path without normalizing it. This seems like it would introduce the minimum number of side-effects (which may be none).

katcoutts commented 3 years ago

Hi @tonyketcham. That's really interesting. On the surface of it I'd also thought it would just require a change to the cloudinary widget code. Happy to take a look at anything. Your suggestion of checking the media_library config does sound the least invasive option.

devnamrits commented 2 years ago

Hi @erezrokah, Thinking to pick this up. Is it too complex as being read out in comments? Accumulating courage for this 😅. I guess, first I need to set cloudinary widget with media-library at media-folder level in config.yml and set up one account in cloudinary to test things out. Right?

erezrokah commented 2 years ago

Hi @devnamrits, this is a bit of a tricky issue since the CMS treats non absolute URLs differently, and also related to https://github.com/netlify/netlify-cms/issues/1934.

We can probably add here https://github.com/netlify/netlify-cms/blob/5ad9d76f2cfbebcff8cfffd307e0060fa9747715/packages/netlify-cms-media-library-cloudinary/src/index.js#L29 logic to output the path, but it will result in a broken preview like #1934.

I removed the good first issue from this for now.

devnamrits commented 2 years ago

Thanks, @erezrokah for your kind reply. So what do you suggest? Should I pick or look for other good first issues??

erezrokah commented 2 years ago

Should I pick or look for other good first issues??

Yes, that should work!

devnamrits commented 2 years ago

Okay @erezrokah, then picking some other good first issues.

solidevolution commented 2 years ago

After I realized that it's currently not possible to get the filename with the full path but my client wants to organize his cloudinary pictures with folders, I didn't set output_filename_only to true. This has the benefit, that my customer has the original picture in his back office. In frontend then I solved it with an simple regex. (javascript)

const originalPicture = 'https://res.cloudinary.com/<CLOUDNAME>/image/upload/<PATH_AND_FILENAME>'
const onlyPathWithName = /\/v\d*\/(.*)/g.exec(originalPicture)[1]

Now with onlyPathWithName I can transform my picture with the cloudinary SDK.

BUT: This is not a cool solution when cloudinary changes their url structure or you switch your cloud name. So a better solution with path and filename in netlify would be needed anyway. It's only a temporary solution.