Warn if file doesn't exist

Let’s say there is the following file: /content/number-1/image.png.

The absolute URL to the file is www.domain.tld/chapter-1/image.png because I set in the front matter url: "chapter-1".

I want Hugo to print a warn if the image is included in the Markdown file (e.g. via {{< figure src="image.png" >}} in the article /chapter-1 or via {{< figure src="/chapter-1/image.png" >}} in any other article) but can not be found on my disk.

I know that there is the function fileExists. But I have no idea how to get the “disk path” (/content/number-1/image.png) of the “absolute URL path” (/chapter-1/image.png).

Without a (non)working sample repository it’s hard to say how to achieve this. I would have a look into ressources, because they have the path to the image, if you work with page bundles.

You can retrieve the path to an image from it’s permalink using the file object:

I’d second page resources being useful for this! I have an effect like this on a custom shortcode that I implemented to resize images.

A couple other ideas that might be helpful:

  • You can copy the figure shortcode into your layouts/shortcodes.html directory and then modify it yourself to perform this check
  • You could also do this for images included in markdown (using ![alt-text](img-url) syntax) using Markdown Render Hooks.

With both of these, you’d have to be careful to make sure that the referenced URL is a local file though, and not (e.g.) a link to an external site.

Depending on your use-case, it might be easier to do this check in a script that runs outside of Hugo as well. I have a similar one that runs to check for go templating errors.

1 Like

capnfabs’ custom shortcode is useful for cases where there are only images referenced which are in the same folder.

In my case there are a lot of cross references so I decided to do that check in a (python) script outside of Hugo as capnfabs suggested. The following script extracts all scr attributes of img tags and checks if the files are in the folder.

import os
from bs4 import BeautifulSoup

# Name of the folder where Hugo generates the website
public_folder = "public" # default: "public"

# Iterate over all files and folders
for root, dirs, files in os.walk(public_folder):
    # For every file...
    for file in files:
        # If file ends with .html (e.g. index.html or _index.html)
        if file.endswith(".html"):
            # Parse HTML
            soup = BeautifulSoup(open(os.path.join(root, file)), "html.parser")
            # For every image...
            for image in soup.findAll('img'):
                # Exclude images with empty src attribute
                if not image['src'] == "":
                    # If src attribute is absolute path (e.g. src="/image-1.jpeg" -> www.domain.tld/image-1.jpeg)
                    if os.path.isabs(image['src']):
                        # Define path to image
                        image_path = os.path.join(os.path.dirname(__file__), public_folder, os.path.normpath(image['src'].strip(os.sep))) # strip(os.sep) removes the leading slash from the path defined in the src attribute (otherwise os.path.join would ignore all previous mentioned directories) 
                    # If src attribute is relative path (e.g. src="image-1.jpeg" -> www.domain.tld/slug-of-current-html/image.jpeg)
                        # Define path to image
                        image_path = os.path.join(os.path.dirname(__file__), root, os.path.normpath(image['src']))
                    # If file doesn't exist
                    if not os.path.isfile(image_path):
                        # Print error message
                        print("ERROR: " + image_path + " referenced in " + os.path.join(root, file) + " wasn't found")

I saved the above script in a file called check-image-path.py in the root folder of my Hugo project (above the public folder generated by Hugo which must be present) and I call it in my command line with python3 check-image-path.py. I use Linux but the script should work an Windows and Mac too.

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.