Search code examples
phpwordpressrestvue.jswordpress-rest-api

Serving real images based on attachment id with wordpress REST API endpoint


Is it possible to serve images with Wordpress Rest API endpoint based on attachment ID?

I mean, if the following link was pasted in browser, i should get the real image instead of JSON response. http://demo.dev/wp-json/custom/v1/image/80

I need it for REST-full Wordpress theme, based on Vue.js and Metabox.io plugin with mb REST API add-on. My metaboxes contain lots of repeatable, nested groups and they output only image ids in array.

I added endpoint in functions.php:

add_action( 'rest_api_init', function () {
    register_rest_route( 'custom/v1', '/image/(?P<id>\S+)', [
        'methods' => WP_REST_Server::READABLE,
        'callback' => 'custom_get_image',
           'args' => [
            'id'
        ],
    ] );
} );

if ( !function_exists('custom_get_image') ){
    function custom_get_image($data){
        $id="";
        $src= get_template_directory_uri().'/img/placeholder.png';
        if ( isset($data['id']) ){
            $image = wp_get_attachment_image_src($data["id"], 'medium');
            if($image){
                $src=$image[0];
            }
        }           
        return $src;
    }
}

Currently, i solved the problem by creating an extra vue component, which calls the API and inserts the file url. However, i wanted to have an API endpoint, that can be added directly to img "src" or div "background-image" without extra ajax call.

<template>
  <img :src="src">
</template>

<script>
import axios from 'axios';
export default {
  props: ['id'],
  data: function() {
    return {
      src: 'http://demo.dev/wp-content/themes/vue-theme/static/img/placeholder.jpg',
    };
  },
  methods: {
    getSrc(id) {
      //var id = 83;
      var endpoint = 'http://demo.dev/wp-json/custom/v1/image/';
      var url = endpoint + id;
      axios
        .get(url)
        .then(response => {
          this.src = response.data;
        })

        .catch(error => {});
    },
  },

  mounted: function() {
    this.$nextTick(function() {
      this.getSrc();
    });
  },
};
</script>

Solution

  • I found working solution in php (may not be the best, wp-load.php must be required). I added a helper script that takes attachment id as a query parameter and redirects to image url:

    <?php
    
    $path = preg_replace('/wp-content.*$/','',__DIR__);
    
    define( 'WP_USE_THEMES', false );
    require( $path.'\wp-load.php' );
    
    $id= isset($_GET['id']) ? $_GET['id'] : '';
    $size= isset($_GET['size']) ? $_GET['size'] : 'fullsize';
    
    $url=$_SERVER['REQUEST_URI'];
    $src=$url."/wp-content/themes/vue-theme/static/img/placeholder.jpg";
    
    if($id){
        $image = wp_get_attachment_image_src( $id, $size );
        if($image){
            $src=$image[0];
        }
    
    }
    
    header("Location: ".$src);
    die();
    ?>
    

    Now i can add url with id like this:

    <div v-for="item in items" class="bg-block" v-bind:style="{ backgroundImage: 'url('+ 'http://demo.dev/wp-content/themes/vue-theme/helpers/service.php?size=medium&id=' + item.imgId +')'></div>;