custom meta box data not saved

So actually, for posts of the type attachment, you should use the edit_attachment (action) hook and not save_post_attachment:

add_action( 'edit_attachment', 'save_image_link' );        // use edit_attachment
//add_action( 'save_post_attachment', 'save_image_link' ); // not save_post_attachment

Secondly, your meta box is not currently displaying the meta value, so you should display the value in the input field, and you can use get_post_meta() to retrieve the meta value:

<input type="text" name="image_link" id="image-link" class="postbox" value="<?php // wrapped
    echo esc_attr( get_post_meta( $post->ID, 'image_link_url', true ) ); ?>">

PS: You should always sanitize/escape user-supplied and untrusted data; e.g. above I use esc_attr() to escape the value, and you can use sanitize_text_field() to sanitize the submitted value: sanitize_text_field( $_POST['image_link'] ).

Sample Implementation Using get_post_gallery() (for the shortcode)

This is based on the example here. And as I’ve mentioned before, you can use get_post_meta() to retrieve the custom field’s value (which in your case is an URL address).

// Get the gallery data (attachment IDs and URLs).
$gallery = get_post_gallery( get_the_ID(), false );
if ( $gallery ) {
    foreach ( wp_parse_id_list( $gallery['ids'] ) as $i => $att_id ) {
        // Get the custom link URL.
        $url = get_post_meta( $att_id, 'image_link_url', true );

        // Display the image. You can add other attributes later..
        echo '<a href="' . esc_url( $url ) . '"><img src="' . // wrapped
            esc_url( $gallery['src'][ $i ] ). '" alt=""></a> ';
    }
}

UPDATE

A Better (Non-Metabox) Solution

If you want to be able to edit the custom field via the Attachment Details dialog, then you should just forget about using the meta box and instead try the following:

  1. This part adds the custom field to the dialog:

    add_filter( 'attachment_fields_to_edit', function ( $form_fields, $post ) {
        $form_fields['image_link'] = array(
            'label' => 'Link to image URL',
            'value' => get_post_meta( $post->ID, 'image_link_url', true ),
        );
    
        return $form_fields;
    }, 10, 2 );
    
  2. This part saves the field as a meta data:

    add_filter( 'attachment_fields_to_save', function ( $post, $attachment ) {
        if ( isset( $attachment['image_link'] ) ) {
            $meta_input = isset( $post['meta_input'] ) ?
                (array) $post['meta_input'] : [];
    
            $meta_input['image_link_url'] = $attachment['image_link'];
    
            $post['meta_input'] = $meta_input;
        }
    
        return $post;
    }, 10, 2 );
    

Note that image_link is the form field (input) name, whereas image_link_url is the meta key.

And this solution also works well with the standard “Edit Media” page — from the Attachment Details dialog, you can get to that page by clicking on the “Edit more details” link.

Full code I used for testing here.

Leave a Comment