2

My question is about how to attached the size dimensions I have successfully extracted from an SVG and force them into the WP 'dimensions' field associated with the file, so that the dimensions appear in the media library.

Note: this is not the same as this earlier question I posted. In that question, I asked how to extract the dimension value. However, no one figured out how to set that value permanently to the SVG so it would display in the media library.

Where I extract the dimensions

I extract the image dimensions from SVGs using a filter. This filter allows me to display the SVGs, not just as logos, but as featured images. The filter I use identifies the size of the SVG from inside the SVG file and then resets the values of image[1] and $image[2] values in the array returned by wp_get_attachment_image_src() This is that function:

File: wp-includes/media.php
804: /**
805:  * Retrieve an image to represent an attachment.
806:  *
807:  * A mime icon for files, thumbnail or intermediate size for images.
808:  *
809:  * The returned array contains four values: the URL of the attachment image src,
810:  * the width of the image file, the height of the image file, and a boolean
811:  * representing whether the returned array describes an intermediate (generated)
812:  * image size or the original, full-sized upload.
813:  *
814:  * @since 2.5.0
815:  *
816:  * @param int          $attachment_id Image attachment ID.
817:  * @param string|array $size          Optional. Image size. Accepts any valid image size, or an array of width
818:  *                                    and height values in pixels (in that order). Default 'thumbnail'.
819:  * @param bool         $icon          Optional. Whether the image should be treated as an icon. Default false.
820:  * @return false|array Returns an array (url, width, height, is_intermediate), or false, if no image is available.
821:  */
822: function wp_get_attachment_image_src( $attachment_id, $size = 'thumbnail', $icon = false ) {
823:    // get a thumbnail or intermediate image if there is one
824:    $image = image_downsize( $attachment_id, $size );
825:    if ( ! $image ) {
826:        $src = false;
827: 
828:        if ( $icon && $src = wp_mime_type_icon( $attachment_id ) ) {
829:            /** This filter is documented in wp-includes/post.php */
830:            $icon_dir = apply_filters( 'icon_dir', ABSPATH . WPINC . '/images/media' );
831: 
832:            $src_file = $icon_dir . '/' . wp_basename( $src );
833:            @list( $width, $height ) = getimagesize( $src_file );
834:        }
835: 
836:        if ( $src && $width && $height ) {
837:            $image = array( $src, $width, $height );
838:        }
839:    }

This is the filter that I apply to that function, which changes the values of $image[1] and $image[2] (i.e. the image width and height, respectively).

 add_filter( 'wp_get_attachment_image_src', 'fix_wp_get_attachment_image_svg', 10, 4 );  /* the hook */

 function fix_wp_get_attachment_image_svg($image, $attachment_id, $size, $icon) {
    if (is_array($image) && preg_match('/\.svg$/i', $image[0]) && $image[1] <= 1) {
        if(is_array($size)) {
            $image[1] = $size[0];
            $image[2] = $size[1];
        } elseif(($xml = simplexml_load_file($image[0])) !== false) {
            $attr = $xml->attributes();
            $viewbox = explode(' ', $attr->viewBox);
            $image[1] = isset($attr->width) && preg_match('/\d+/', $attr->width, $value) ? (int) $value[0] : (count($viewbox) == 4 ? (int) $viewbox[2] : null);
            $image[2] = isset($attr->height) && preg_match('/\d+/', $attr->height, $value) ? (int) $value[0] : (count($viewbox) == 4 ? (int) $viewbox[3] : null);
        } else {
            $image[1] = $image[2] = null;
        }
    }
    return $image;
} 

Filter works, but media library doesn't show extracted data

The filter works, and from what I can tell this information in $image[1] and $image[2] are being assigned to the html width and height of the element of the placed SVG. But, as you can see in the image below, the filter doesn't seem to be updating the image's dimensions field in the WP database.

library view of SVG vs PNG

My question summarized:

How do I take these dimension values, that my filter retrieves, and get them attached to the image file in the database itself in a way that allows me to view the dimensions in the media library?

Thanks!!

7
  • Could you log the wp_get_attachment_metadata and see if the width and height are not null or empty?
    – Laxmana
    Feb 14, 2017 at 19:40
  • Can you explain this? how do i log this? Feb 14, 2017 at 19:48
  • You can either var_dump/echo/print_r the returned value of wp_get_attachment_metadata or use the error_log() function to print the value to the debug.log file. More here: codex.wordpress.org/Debugging_in_WordPress#WP_DEBUG_LOG
    – Laxmana
    Feb 14, 2017 at 19:50
  • So I added this code: $myMetaD = wp_get_attachment_metadata ( get_post_thumbnail_id( get_the_ID() ) ); var_dump($myMetaD); ... This is what is is echoed: string(0) "" (markdown isn't working for some reason). I checked and 1) yes, I am returning the post id as I should, and 2) the thumbnail id is also returning the correct value. Feb 15, 2017 at 17:26
  • Where you var_dump the variable ? It should be outside the filter function (after the metadata have been saved). I.e. in single.php
    – Laxmana
    Feb 15, 2017 at 17:50

1 Answer 1

5
+50

The wp_update_attachment_metadata filter fires every time you upload an image through media library (specifically every time wp_update_attachment_metadata function is being called).

So when an svg file is uploaded we check if the file has the desired metadata, the width and height. If not, we generate the metadata as you did in your wp_get_attachment_image_src filter. Now that the metadata are saved we can call functions like wp_get_attachment_image_src and get the metada without the need to filter those functions.

Be aware of the problem of uploading svg files in the latest Wordpress version (4.7.2). It supposed to be fixed in 4.7.3

Lastly I would like to warn you about the potential security risks (XSS attacks) that svg files expose. More here and here.

function svg_meta_data($data, $id){

    $attachment = get_post($id); // Filter makes sure that the post is an attachment
    $mime_type = $attachment->post_mime_type; // The attachment mime_type

    //If the attachment is an svg

    if($mime_type == 'image/svg+xml'){

        //If the svg metadata are empty or the width is empty or the height is empty
        //then get the attributes from xml.

        if(empty($data) || empty($data['width']) || empty($data['height'])){

            $xml = simplexml_load_file(wp_get_attachment_url($id));
            $attr = $xml->attributes();
            $viewbox = explode(' ', $attr->viewBox);
            $data['width'] = isset($attr->width) && preg_match('/\d+/', $attr->width, $value) ? (int) $value[0] : (count($viewbox) == 4 ? (int) $viewbox[2] : null);
            $data['height'] = isset($attr->height) && preg_match('/\d+/', $attr->height, $value) ? (int) $value[0] : (count($viewbox) == 4 ? (int) $viewbox[3] : null);
        }

    }

    return $data;

}

add_filter('wp_update_attachment_metadata', 'svg_meta_data', 10, 2);
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.