Journal

How do you print an image alt from a custom field in WordPress?

Store the image as an attachment ID if you can. If the custom field only saved a URL, turn that URL into an attachment ID and read _wp_attachment_image_alt. That is the alt someone already typed in the media library. Printing the post title instead is a fallback, and it is the wrong text whenever the picture is not the post.

This assumes you already know how the meta field was registered. The note was first published on December 8, 2018. The function names below are still the ones WordPress uses.

$image_url = get_post_meta( get_the_ID(), 'post-meta-field-id', true );
$image_id  = attachment_url_to_postid( $image_url );
$alt       = get_post_meta( $image_id, '_wp_attachment_image_alt', true );

echo esc_attr( $alt );

post-meta-field-id is the meta key you chose when you registered the field. Advanced Custom Fields will give you an array or an ID instead of a bare URL, and in that case you should use the ID it stored and skip attachment_url_to_postid(). I have usually registered these fields myself so a project does not load a plugin it does not need. Either way, the alt you want is _wp_attachment_image_alt on the attachment post.

attachment_url_to_postid() looks through the database for that URL. Calling it for every image in a huge loop is a good sign the page is doing too much work, which is its own problem. Saving the attachment ID in the field avoids the lookup.

In the template:

<img
  src="<?php echo esc_url( $image_url ); ?>"
  alt="<?php echo esc_attr( $alt ); ?>"
>

Escape both. An alt is an attribute, so esc_attr() is the right function. If the media library alt is empty, write one. An empty alt is correct only for a decorative image, and a content image in a template rarely is.

The 2018 version of this post was missing alt text on most of its own screenshots. Those screenshots are not carried over. The code is.

If the images are also the reason the page is heavy, the next conversation is performance, not another meta key.