WordPress Plugins and Themes

display new credit field from media library image metadata

16 Replies ·

  1. I’ve used (slightly modified) info from here to add image credit meta to media attachments

    //add credit field in media library image metadata
    function railtrail_add_attachment_credit( $form_fields, $post ) {
        $field_value = ( get_post_meta($post->ID, "_credit_text", true) );
        $form_fields[ 'credit_text' ] = array(
            'value'    => $field_value ? $field_value : '',
            'label'    => __( 'Credit' ),
            'helps'    => __( 'Insert image owners name' )
        );
        return $form_fields;
    }
    
    add_filter( 'attachment_fields_to_edit', 'railtrail_add_attachment_credit', 10, 2);
    
    
    function railtrail_save_attachment_credit( $attachment_id ) {
        if ( isset( $_REQUEST['attachments'][$attachment_id]['credit_text'] ) ) {
            $credit_text = $_REQUEST['attachments'][$attachment_id]['credit_text'];
            update_post_meta( $attachment_id, '_credit_text', $credit_text );
        }
    }
    
    add_action( 'edit_attachment', 'railtrail_save_attachment_attribution' );
    

    Is this a good way to achieve this?
    Does this input need escaping/sanitizing ?

    Could you help with filtering the image caption shortcode to output the credit_txt as an extra paragraph appended to the caption, preceded by something like “Photo supplied by:”.

    At least that is how I think it would be done after looking through media.php

    My attempts seem to break things.

  2. Justin Tadlock

    Your save function should be something more along these lines (untested):

    function railtrail_save_attachment_credit( $attachment_id ) {
    
        $credit_text     = '';
        $old_credit_text = get_post_meta( $attachment_id, "_credit_text", true );
    
        if ( isset( $_REQUEST['attachments'][$attachment_id]['credit_text'] ) ) {
    
            $credit_text = sanitize_text_field( 
                wp_unslash( $_REQUEST['attachments'][$attachment_id]['credit_text'] )
            );
        }
    
        if ( $credit_text && $credit_text != $old_credit_text ) {
    
            update_post_meta( $attachment_id, '_credit_text', $credit_text );
    
        } elseif ( ! $credit_text && $old_credit_text ) {
    
            delete_post_meta( $attachment_id, '_credit_text' );
        }
    }
    

    That adds sanitization and also a way to delete the text if it’s removed.

    Let me look into the image caption shortcode.

  3. Justin Tadlock

    For the caption filter, you’ll need something like the following. This is mostly just copied directly from the img_caption_shortcode() function in wp-includes/media.php.

    add_filter( 'img_caption_shortcode', 'railtrail_caption_shortcode', 10, 3 );
    
    function railtrail_caption_shortcode( $output, $attr, $content ) {
    
        $id = isset( $attr['id'] ) ? $attr['id'] : 0;
    
        $credit_text = '';
    
        if ( $id ) { 
            $credit_text = get_post_meta( $id, "_credit_text", true );
        }
    
        // Pass this back to WP if there's no credit text.
        if ( ! $credit_text ) {
            return $output;
        }
    
        $atts = shortcode_atts(
            array(
                'id'         => '',
                'caption_id' => '',
                'align'      => 'alignnone',
                'width'      => '',
                'caption'    => '',
                'class'      => '',
            ), $attr, 'caption'
        );
    
        $atts['width'] = (int) $atts['width'];
        if ( $atts['width'] < 1 || empty( $atts['caption'] ) ) {
            return $content;
        }
    
        $id = $caption_id = $describedby = '';
    
        if ( $atts['id'] ) {
            $atts['id'] = sanitize_html_class( $atts['id'] );
            $id         = 'id="' . esc_attr( $atts['id'] ) . '" ';
        }
    
        if ( $atts['caption_id'] ) {
            $atts['caption_id'] = sanitize_html_class( $atts['caption_id'] );
        } elseif ( $atts['id'] ) {
            $atts['caption_id'] = 'caption-' . str_replace( '_', '-', $atts['id'] );
        }
    
        if ( $atts['caption_id'] ) {
            $caption_id  = 'id="' . esc_attr( $atts['caption_id'] ) . '" ';
            $describedby = 'aria-describedby="' . esc_attr( $atts['caption_id'] ) . '" ';
        }
    
        $class = trim( 'wp-caption ' . $atts['align'] . ' ' . $atts['class'] );
    
        $caption_width = apply_filters( 'img_caption_shortcode_width', $atts['width'], $atts, $content );
    
        $style = '';
        if ( $caption_width ) {
            $style = 'style="width: ' . (int) $caption_width . 'px" ';
        }
    
        $html = sprintf(
            '<figure %s%s%sclass="%s">%s%s</figure>',
            $id,
            $describedby,
            $style,
            esc_attr( $class ),
            do_shortcode( $content ),
            sprintf(
                '<figcaption %sclass="wp-caption-text">%s <span class="credit-text">%s</span></figcaption>',
                $caption_id,
                $atts['caption'],
                esc_html( $credit_text )
            )
        );
    
        return $html;
    }
    
  4. markmcl

    It does not appear to be saving to the database. At least, it is not displaying on the front end. I looked through the postmeta using phpmyadmin, which is where I presume it would save. I’m not experienced in the database, but I cannot see anything in the correct post id except

    350     _wp_attached_file   2018/06/hogback-sleepers.jpg
    350     _wp_attachment_metadata     a:5:{s:5:"width";i:1007;s:6:"height";i:971;s:4:"fi...
    350     _wp_attachment_image_alt    hogback sleepers in the railway tunnels on the Daw...
    

    There is nothing relating to the credit field when browsing_wp_attachment_metadata which is where I thought it would be, or the other two for that matter.

    Curiously it stays in the field in the media library window after logging out in Firefox, log in using Chrome incognito and there it is.

    Credit     Image by: M McLachlan
                  Insert image owners name
    
  5. Justin Tadlock

    I’ve been offline most of today. I’ll get this set up on my computer in the morning and see if I can figure it out. It’s a bit much to look over without more testing.

  6. markmcl

    A new day and a new search found this which works and has the added benefit of adding a link.

    He references your post from 2011 which I had read a couple of nights ago.

    I changed this:

    (shortcode_atts(array(
            'id'    => '',
            'align' => 'alignnone',
            'width' => '',
            'caption' => ''
        ), $attr));
    

    to this

     extract (shortcode_atts( array(
            'id'      => '',
            'align'   => 'alignnone',
            'width'   => '',
            'caption' => '',
            'class'   => '',
        ), $attr, 'caption' ));
    

    and this:

    if($source_credit = get_post_meta($att_id[0], 'source_credit', true)) {
                $caption .= ' – <a class="source-credit" href="'. $source_url .'">'. $source_credit .'</a>';   
            }
    

    to this:

    if($source_credit = get_post_meta($att_id[0], 'source_credit', true)) {
                $caption .= ' <br />Photo by: <a class="source-credit" href="'. $source_url .'">'. $source_credit .'</a>';   
            }
    

    but when I try to get the link to open in a new tab by adding target="_blank" rel="noopener" it redirects to .404, so I am not getting that right, if you could help with that it would be good.

    A new day and a little more reading and I find the caption is treated as the excerpt in the posts table. Learning, learning. However, I still can’t find where data from the added fields is stored. I expected it would be with the caption.

    Re: That adds sanitization and also a way to delete the text if it’s removed.

    Adding a way of deleting the text if it’s removed would be good.
    Removing the text from the fields removes it from the front end.
    Should the text fields in his code be sanitized?

  7. Justin Tadlock

    but when I try to get the link to open in a new tab by adding target=”_blank” rel=”noopener” it redirects to .404, so I am not getting that right, if you could help with that it would be good.

    To add your target and rel attributes, you need to change this code:

    if($source_credit = get_post_meta($att_id[0], 'source_credit', true)) {
                $caption .= ' <br />Photo by: <a class="source-credit" href="'. $source_url .'">'. $source_credit .'</a>';   
            }
    

    To this:

    if ( $source_credit = get_post_meta( $att_id[0], 'source_credit', true ) ) {
    
        $caption .= sprintf(
            ' <br />Photo by: <a class="source-credit" href="%s" target="_blank" rel="noopener">%s</a>',
            esc_url( $source_url ),
            esc_html( $source_credit )
        );
    }
    

    I also added in some escaping of the data so that it’d be secure on output.

    A new day and a little more reading and I find the caption is treated as the excerpt in the posts table. Learning, learning. However, I still can’t find where data from the added fields is stored. I expected it would be with the caption.

    Post meta (what this is) is stored in the *_postmeta table in your database.

    Adding a way of deleting the text if it’s removed would be good.
    Removing the text from the fields removes it from the front end.
    Should the text fields in his code be sanitized?

    The save_image_source_url() function needs to be fixed for all of these.

    function save_image_source_url($post, $attachment) {
    
        $old_url    = get_post_meta( $post['ID'], 'source_url',    true );
        $old_credit = get_post_meta( $post['ID'], 'source_credit', true );
    
        $source_url = isset( $attachment['source_url'] ) ? $attachment['source_url'] : '';
        $source_credit = isset( $attachment['source_credit'] ) ? $attachment['source_credit'] : '';
    
        if ( $source_url && $source_url != $old_url ) {
    
            update_post_meta( $post['ID'], 'source_url', esc_url_raw( $source_url ) );
    
        } elseif ( $old_url ) {
    
            delete_post_meta( $post['ID'], 'source_url' );
        }
    
        if ( $source_credit && $source_credit != $old_credit ) {
    
            update_post_meta( $post['ID'], 'source_credit', sanitize_text_field( $source_credit ) );
    
        } elseif ( $old_credit ) {
    
            delete_post_meta( $post['ID'], 'source_credit' );
        }
    
        return $post;
    }
    
  8. markmcl

    the save_image_source_url() function has a problem of some kind.
    Using the old version allows it all to work (with other changes working.)

  9. markmcl

    It certainly does.
    Many Thanks.
    This is for another community website with several authors and photo sources – so their thanks as well.

    I use Diffmerge to compare the code and to learn.

    If your code was a newly planted crop, every seed would germinate, the rows of plants would be straight, the organic fertiliser perfectly balanced and the crop abundant.

  10. markmcl

    I went back through the site to add source and links to various images.
    If only one field is used, eg Photo credit without link field being used, it does not display on the front end.

    If the link field alone is used it wraps the credit in a link, as expected, but does not open the link in a new tab, rather opens it in the same page.

  11. markmcl

    Since the advent of the new editor, these fields have to be accessed after using the image block to insert the image in the content by editing the image. (click on pencil image to open editing)

    However they do not now show in the caption.

    I had searched for “how to save media data to gutenburg image block” and came up with
    https://github.com/WordPress/gutenberg/issues/11333
    and
    https://gist.github.com/joemcgill/dbec1854cd02d63b731c583f4a751e7c
    which could be an answer but I do not seem to be able to advance things after messing around with it

  12. Justin Tadlock

    I haven’t been able to find anything. I’m not really sure how it’s handled myself.

    Just to be clear, you’re wanting to get the “credit” to appear in the new editor, right? It’s already appearing on the front end?

    Did the credit line appear in the old editor?