Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

'relative path' field for uploaded images #325

Closed
m4rrc0 opened this issue Mar 27, 2017 · 51 comments · Fixed by #2394
Closed

'relative path' field for uploaded images #325

m4rrc0 opened this issue Mar 27, 2017 · 51 comments · Fixed by #2394

Comments

@m4rrc0
Copy link

m4rrc0 commented Mar 27, 2017

Hi,
I am starting to use Netlify CMS with Gatsby 1.0.
I need a relative path to fetch pictures with the graphQL layer. So in my frontmatter I would like to have a field like:
fieldName: ../images/myImage.jpg
Of course the last part ("myImage.jpg") would be different for each entry depending on the file I upload.

Is there a way to auto generate a string field in the frontmatter that would concatenate a string of my choice (for example '../images/') with the name of a picture I may upload in an image field of the same entry ?

I also tried to set:
public_folder: "../images"
This would theoretically change all my image fields in all collections to get that leading string in the file path but when I create a new file with the CMS I get an auto opening '/'... So in my frontmatter:
image: /../images/myImage.jpg
instead of
image: ../images/myImage.jpg
Of course this breaks my groove as well.

What is the best way to get around this issue?

@erquhart
Copy link
Contributor

@MarcCoet a simple, non-breaking approach would be to accept a public_folder_relative setting in the config - set it to true to avoid the prepended slash. If you're up for giving this a shot, implementation would probably look like this:

  1. Update the resolvePath helper to accept a third option allowRelative.
  2. Update the two places in that function where slashes are prepended to only do so if the allowRelative param is not truthy.
  3. Update the assetProxy function to pass in the new config value as a third param to resolvePath.

@erquhart
Copy link
Contributor

This issue should be at least helped by #350.

@brandonmp
Copy link

@MarcCoet FWIW a quick workaround is to just edit the markdown of your post to the correct relative path from within netlify cms (ie, just toggle the 'Markdown' switch and edit the path)

It'll break the preview, but so far it appears to push fine. here's my config:

...
media_folder: content/blog-posts/media
public_folder: ../media/
collections:
  - name: blog
    label: Blog
    folder: content/blog-posts/posts
...

@erquhart
Copy link
Contributor

erquhart commented Dec 8, 2017

I still think this use case should be supported, but it merits further discussion.

@fk
Copy link

fk commented Dec 11, 2017

Hey! 👋 I took a first quick shot at what @erquhart outlined in #325 (comment) over the weekend.

Previews don't work yet (haven't looked into the code much) but this does enough to let a friend of mine that I'm helping with his portfolio site author his stuff – relative paths are correctly inserted in Markdown. My context is exactly like discussed in #843 (using Gatsby).

I would love to provide a PR for this eventually but most probably will need some guidance.

@erquhart
Copy link
Contributor

@fk that's awesome!

In the time since I wrote that comment, I've come to avoid "switches" that affect other settings in the config. A better approach that's still non-breaking would be to just check if the path begins with one or two dots and a slash and don't prepend a slash if so. We'd want to test it out a bit for unexpected consequences, though. Are you up for giving that a shot?

@fk
Copy link

fk commented Dec 19, 2017

Hey @erquhart! Yes! Up for anything! ;-) :-D

I also have been thinking a little about how to approach this feature in the meantime. I didn't have much time, so I only came as far as to look into assetProxy in regards on how to restore media previews in the editor and preview pane.

I also started to wonder if approaching this change from what I believe is a quite specific, "Gatsby" point of view, is the right thing to do to actually land a PR that is beneficial to anyone else – in other words: "What are other use cases for a relative public path (which couldn't be resolved by just changing the location of the media folder)?" is a question I figured I should ask here before going any further.

A quick recap of my specific use case: For Gatsby to be able to process URLs in Markdown (process images, copy linked files), it requires them to be relative (I still have to check back with @KyleAMathews on that, but I think "it's a Webpack thing") – basically what surfaced in #843.
My initial approach was to add the public_folder_relative option as you suggested (and then somehow make previews work with that), and to put all my markdown content at the same "distance" to the media folder – e.g. if my public_folder_relative was ../../img, all my Markdown content would have to live two folders down from img per convention.

Ideally I thought netlify-cms could resolve the path to be inserted in Markdown relative to the Markdown source and the location of the media folder. But somehow I feel like I'm missing something obvious still…

I've come to avoid "switches" that affect other settings in the config. A better approach that's still non-breaking would be to just check if the path begins with one or two dots and a slash and don't prepend a slash if so.

Yes, totally can follow your thoughts. FWIW, I've been seeing sindresorhus/is-relative-url being used in Gatsby.

We'd want to test it out a bit for unexpected consequences, though. Are you up for giving that a shot?

Yes! How about I adjust my fork to look at the path/remove the new public_folder_relative option and report back?

@erquhart
Copy link
Contributor

@fk apologies for the delay - that would be awesome. The problem and solution can really approached quite abstractly: for myriad reasons, folks sometimes want to set their media folder via relative path. I can't think of other specific use cases off the top of my head.

@tech4him1
Copy link
Contributor

tech4him1 commented Dec 25, 2017

Hugo is going to be supporting image processing soon (before Jan 1!), and if I understand correctly, it will only work with relatively placed images. We probably want to prioritize this a little more.

@tech4him1
Copy link
Contributor

@erquhart I don't quite understand how the media library will handle relatively placed media. Will it just walk through all the directories to find files that match the media_folder string (via regex?)?

Also, what do we do if an image is added to one entry, and then it is added to a different post via the media library? Do we just add the path relatively to the old location, or would we copy the actual image to the second location as well?

@ilyabo
Copy link

ilyabo commented Dec 30, 2017

I found another workaround. Maybe it will be useful for somebody else. The path added to the markdown files by Netlify CMS can be adjusted and set (as Gatsby requires) to the relative path from the particular node (markdown file) the image is used in. Adding the following code to gatsby-node.js did the trick for me:

exports.onCreateNode = ({
  node,
  getNode,
  loadNodeContent,
  boundActionCreators,
}) => {
  const { frontmatter } = node
  if (frontmatter) {
    const { image } = frontmatter
    if (image) {
      if (image.indexOf('/img') === 0) {
        frontmatter.image = path.relative(
          path.dirname(node.fileAbsolutePath),
          path.join(__dirname, '/static/', image)
        )
      }
    }
  }
}

This assumes that config.yml has the media file paths set as follows:

media_folder: "static/img"
public_folder: "/img"

Also, the name of the markdown fields this would apply for is hardcoded above as image.

@KyleAMathews
Copy link
Contributor

You shouldn't mutate node data. The data should be treated as immutable (I'm actually surprised that worked as I thought we were already passing a copy of data to APIs to prevent exactly this sort of thing. Instead use https://www.gatsbyjs.org/docs/bound-action-creators/#createNodeField

@ilyabo
Copy link

ilyabo commented Dec 30, 2017

Ok, makes sense. I actually tried to use the spread operator to avoid mutation, but somehow it didn't work. Will try with createNodeField

@ghost
Copy link

ghost commented Dec 30, 2017

how would the graphQL query look like with createNodeField?

This works:


markdownRemark{
     frontmatter {
        image
      }
      fields {
        imageRel
      }
}

But nicer would be:

markdownRemark{
     frontmatter {
        image {
          relativePath 
            // and then here the childImageSharp stuff
        }
      }
}

which fails with: GraphQL Error Field "image" must not have a selection since type "String" has no subfields.

@KyleAMathews
Copy link
Contributor

If you want to link to a file node, you need to add ___NODE to the end of the field name so image___NODE

@ahoward
Copy link

ahoward commented Apr 12, 2018

fwiw, a 'public_folder' config containing an absolute url is also munged with a leading /WHACK -> -- after having much discussion in gitter, and reading (grepping really...) the source i think the global, and correct, fix is to never touch 'public_folder' , eg. never prepend a /...

understanding that this could break existing customers but, also, from a naming perspective my suggestion is similar to others in that i'd add another key, eg 'media_prefix' and prefer that when expanding links in content. this value should be a promise that would always resolve a media item whether static or dynamic. it would have a very, very simple contract: media_prefix + '/' + media_filename is valid. what that might be so is the customer's problem - not netlify's

@PaulEibensteiner
Copy link

Hi everyone!
I had the problem of using Hugos image processing while at the same time maintaining the easy image adding that netlify cms provides.
I used the method talves provided to store all media in a folder in the content directory. Then I created a shortcode which resizes the image and inserts the link. Now I created a custom editor widget for the netlify cms which inserts the shortcode by using the media library and edits the paths, so preview and output work.
I can provide all the files if anyone's interested
(This is my first post in a github discussion - I hope I'm in the right place ˆˆ)

@erquhart
Copy link
Contributor

erquhart commented Jun 1, 2018

Hi @PaulEibensteiner - welcome, you're in the right place! And your solution sounds awesome! Can you put your code in a gist and provide a link?

@talves
Copy link
Collaborator

talves commented Jun 1, 2018

@PaulEibensteiner great job. I was planning to eventually get to creating a widget for a Hugo shortcode, but have been really busy with some other fun stuff that will be coming soon.

@PaulEibensteiner
Copy link

PaulEibensteiner commented Jun 1, 2018

Sure!
So first you have to create the directory "images" in your content directory, and add the _index.md with following front matter:

---
title: Media Folder
headless: true
---

Then the shortcode in the layouts/shortcodes directory:
https://gist.github.com/PaulEibensteiner/c88e14439abc1111f7388520ade2cf36

Now the custom editor widget: I have a 1-year knowledge of self taught javascript so this might be a complete mess - also I didn't quite understand the documentation about building a custom widget. So I just added the following code at the bottom of my static/admin/index.html (after the <script src="https://unpkg.com/netlify-cms@^1.0.0/dist/cms.js"></script> tag):
https://gist.github.com/PaulEibensteiner/c2f1d107deef3a0d7d30fa25ef0a198e
I know that the method to remove and add the path sequence for the folder is really messy. Ideal would probably be to access the public_folder and media_folder configuration and change the path accordingly, I just don't have a clue how to to that - and it works so whatever...
(You could also remove the path like others did in the shortcode via go...but there you wouldn't even have the option to change it based on the folder name I guess)

  • now you only have to move all your images to the new location and change all links to the new shortcodes...and it should work

ps: I might have messed up the naming of elements because I already changed some stuff in the original project but omitted it here for 'simplicity' - I hope it works. Pls let me know if anything is flawed or if my explanations are confusing
Have fun coding - Hugo's pretty awesome ˆˆ

@talves
Copy link
Collaborator

talves commented Jun 1, 2018

@PaulEibensteiner This is good stuff. Don't worry about the widget, I will eventually formalize yours into an npm module if you don't get to it first. Again, great job. Also, yes Hugo is pretty Awesome!

@PaulEibensteiner
Copy link

@talves Thank you, yeah, I don't really know about npm and that stuff ˆˆ But that would be awesome...
Quick question off-topic: Are there custom widgets provided by other users somewhere on the internet? I could imagine there are a lot of examples (like the yt widget in the docs) which a lot of people would find useful? Googled and didn't find anything...

@talves
Copy link
Collaborator

talves commented Jun 1, 2018

We have been discussing creating a place for people to publish information about their custom widgets on the NetlifyCMS site somewhere. You are right, and a plan to have a full information format will help quite a bit. I am sure we will get there. We just need someone in the community to take it on when they get time. I might tackle it with some other stuff I am doing, but it is lower on the priority at the moment.

I created an issue for discussion here, rather than us keep hijacking this issue.

@bmingles
Copy link

@zionis137 Responding to an old comment of yours #325 (comment)

If you use createNodeField to convert frontmatter.image to a relative path in gatsby-node.js:

createNodeField({
  node,
  name: 'imageRel',
  value: someConversionToFileSystemPath(node.frontmatter.image)
});

then you should be able to query your image node like this:

markdownRemark{
    frontmatter {
        image // this will still be original string that couldn't resolve to file system path
    }
    fields {
        imageRel { // this will contain a file node
            relativePath 
            // and then here the childImageSharp stuff
        }
    }
}

As I understand it, any paths that Gatsby can identify as a file system path will be converted to file nodes in the query results in which case you can access relativePath, and childImageSharp, etc.

@johnclark456
Copy link

Thanks, that works great, I used a trick like this to let me leave the images in src/static whilst letting me process them in remark-images. Doing that means the netlify CMS previews work as expected as well.

@jslyonnais
Copy link

I've found this working damn great!
Image Loading with Gatsby v2 and Netlify CMS v2
Can also find the link to the dude repos in the article if you wanna see the full config.

@joshuarule
Copy link

Has anyone tried this with an animated gif file? I previously used @danielmahon plugin and had that working...but when my client just decided they wanted a gif...I'm now getting errors that childImageSharp is null. Does it behave differently with a gif vs jpg? I had looked at this...but on first try didn't have much luck https://www.gatsbyjs.org/packages/gatsby-remark-copy-linked-files/?=copy-

@danielmahon
Copy link
Contributor

@joshuarule check the ‘gatbsy-image’ docs but I think GIFs and SVGs aren’t supported...maybe?

@johnclark456
Copy link

@joshuarule I'm assuming this is still the case? gatsbyjs/gatsby#7317 (comment)

s0 added a commit to s0/netlify-cms that referenced this issue Jun 20, 2019
relative paths of media files

fixes decaporg#325
s0 added a commit to s0/netlify-cms that referenced this issue Jun 20, 2019
erquhart pushed a commit that referenced this issue Aug 24, 2019
* Allow for relative paths of media files

fixes #325

* Switch to calculating the relative path based on collection

The required relative path is now calculated depending on the
location of the collection of the current entry having the
media inserted into. And the configuration option has now been
changed to a boolean flag.

This allows collections to not neccesarily all be in the same
location relative to the media folder, and simplifies config.

* Clean up code and fix linting

* Add unit tests to resolveMediaFilename()

* Rework insertMedia action to fetch own config

This moves more of the media path resolution logic into the action
which makes it easier to unit test

* Add unit tests for the mediaLibrary.insertMedia action

* yarn run format

* add dependabot config (#2580)
nathankitchen pushed a commit to nathankitchen/netlify-cms-backend-azure that referenced this issue Feb 24, 2020
* Allow for relative paths of media files

fixes decaporg#325

* Switch to calculating the relative path based on collection

The required relative path is now calculated depending on the
location of the collection of the current entry having the
media inserted into. And the configuration option has now been
changed to a boolean flag.

This allows collections to not neccesarily all be in the same
location relative to the media folder, and simplifies config.

* Clean up code and fix linting

* Add unit tests to resolveMediaFilename()

* Rework insertMedia action to fetch own config

This moves more of the media path resolution logic into the action
which makes it easier to unit test

* Add unit tests for the mediaLibrary.insertMedia action

* yarn run format

* add dependabot config (decaporg#2580)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.