1

The goal with this is to create a random banner, managed in the wp admin. I can create a banner solution in the wp admin without an issue but need a little help on the ajax side.

I have an image http://example.com/wp-content/uploads/2015/12/image-name.jpg

I created a random_banner function in functions.php.

add_action( 'wp_ajax_random_banner', 'random_banner' );
add_action( 'wp_ajax_nopriv_random_banner', 'random_banner' );

function random_banner() {
    $image = file_get_contents( 'http://example.com/wp-content/uploads/2015/12/image-name.jpg' );
    header( 'Content-type: image/jpeg;' );
    header( "Content-Length: " . strlen( $image ) );
    echo $image;
}

BTW I have tested this outside of wp and it works great.

Anyway, I then link to this function in an image src like:

<img src="http://example.com//wp-admin/admin-ajax.php?action=random_banner">

This currently returns a broken image icon in chrome. The permissions on my uploads folder is 775.

Not sure what else to try.

4
  • 1
    normally you need to exit; the ajax
    – jycr753
    Jan 20 '16 at 21:08
  • a simpler method would be to pass an URL back and set the src attribute in your javascript. or even simpler would be to pass all of the images to the script via wp_localize_script and randomly selecting one in js. requesting a static image is much faster than loading all of WordPress just to end up outputting an image.
    – Milo
    Jan 20 '16 at 21:12
  • thanks @jycr753. I added that, but that didn't solve the broken image. Jan 20 '16 at 21:33
  • @Milo I am open to this, but the admin experience is that they will set this url in the admin for a banner. The url gets output in the template for the banner image. And I don't have control over the template, so this has to be pretty flexible. Jan 20 '16 at 21:34
3

There is an error in your src;

<img src="http://example.com//wp-admin/admin-ajax.php?action=random_banner">

Try this one:

<img src="http://example.com/wp-admin/admin-ajax.php?action=random_banner">

or

<img src="<?php echo admin_url( 'admin-ajax.php?action=random_banner' ); ?>">

You can also use a query to get a random image.

AJAX

add_action( 'wp_ajax_random_banner', 'random_banner' );
add_action( 'wp_ajax_nopriv_random_banner', 'random_banner' );

function random_banner() {

    // search for 1 random image

    $image_ids = get_posts(
        array(
            'post_type'      => 'attachment',
            'post_mime_type' => 'image',
            'post_status'    => 'inherit',
            'numberposts'    => 1,
            'orderby'        => 'rand',
            'fields'         => 'ids',
        ) );

    // convert id to url

    $images = array_map( "wp_get_attachment_url", $image_ids );

    $image_id = $image_ids[ 0 ];
    $image_url = $images[0];

    // make sure path is readable -- if not, stop!

    // this won't work with URL :(
    // if( !is_readable($image_url)) {
    //    wp_die( "File is not readable: $image_url" );
    // }

    $image    = file_get_contents( $image_url );
    $type     = get_post_mime_type( $image_id );
    if ( empty ( $type ) ) {
        $type = "image/jpg";
    }

    // output headers and image data

    nocache_headers();
    header( "Content-type: $type;" );
    header( "Content-Length: " . strlen( $image ) );

    echo $image;
    die();
}

Update | Endpoint Alternate

Skip the AJAX call and just create an API endpoint for your random image function using add_rewrite_rule().

IMAGE

<img src="http://example.com/api/images/random">

PHP

/**
 * Creates endpoint to select random image from Library
 *
 * http://example.com/api/images/random
 *
 */
if ( ! class_exists( 'Endpoint_RandomImage' ) ):
    /**
     * The code that registers the endpoint and handles the result
     */
    class Endpoint_RandomImage {

        const ENDPOINT_NAME       = 'api/images/random'; // endpoint to capture
        const ENDPOINT_QUERY_NAME = '__api_images_random'; // turns to param

        // WordPress hooks
        public function run() {
            add_filter( 'query_vars', array( $this, 'add_query_vars' ), 0 );
            add_action( 'parse_request', array( $this, 'sniff_requests' ), 0 );
            add_action( 'init', array( $this, 'add_endpoint' ), 0 );
        }

        // Add public query vars
        public function add_query_vars( $vars ) {
            $vars[] = static::ENDPOINT_QUERY_NAME;
            $vars[] = 'extra';

            return $vars;
        }

        // Add API Endpoint
        public function add_endpoint() {
            add_rewrite_rule( '^' . static::ENDPOINT_NAME . '?$', 'index.php?' . static::ENDPOINT_QUERY_NAME . '=1', 'top' );
            add_rewrite_rule( '^' . static::ENDPOINT_NAME . '/([^/]+)/?$', 'index.php?' . static::ENDPOINT_QUERY_NAME . '=1&extra=$matches[1]', 'top' );
// --->
            flush_rewrite_rules( true ); //// <---------- REMOVE THIS WHEN DONE TESTING
// --->
        }

        // Sniff Requests
        public function sniff_requests( $wp_query ) {

            global $wp;

            if ( isset( $wp->query_vars[ static::ENDPOINT_QUERY_NAME ] ) ) {
                $this->handle_request(); // handle it
            }
        }

        // Handle Requests
        protected function handle_request() {
            global $wp;

            $image_ids = get_posts(
                array(
                    'post_type'      => 'attachment',
                    'post_mime_type' => 'image',
                    'post_status'    => 'inherit',
                    'numberposts'    => 1,
                    'orderby'        => 'rand',
                    'fields'         => 'ids',
                ) );

            // convert ids to urls
            // $images = array_map( "wp_get_attachment_url", $image_ids );

            // convert ids to paths
            $images = array_map( "get_attached_file", $image_ids );

            $image_id   = $image_ids[ 0 ];
            $image_path = $images[ 0 ];

            // make sure url is readable -- if not, stop!
            if ( ! is_readable( $image_path ) ) {
                wp_die( "File is not readable: $image_path" );
            }

            $image = file_get_contents( $image_path );
            $type  = get_post_mime_type( $image_id );
            if ( empty ( $type ) ) {
                $type = "image/jpg";
            }

            // output headers and image data

            nocache_headers();
            header( "Content-type: $type;" );
            header( "Content-Length: " . strlen( $image ) );

            echo $image;
            die();
        }
    }

    $ep = new Endpoint_RandomImage();
    $ep->run();

endif; // Endpoint_RandomImage

Endpoint Alternate #2

<img src="http://example.com/api/random-banner/">

Using the rewrites + query tags.

<?php

if ( ! class_exists( 'Prefix_API' ) ) {

    class Prefix_API {

        function __invoke() {
            add_action( 'init', array ( $this, 'prefix__init' ) );
            add_action( 'pre_get_posts', array ( $this, 'prefix__pre_get_posts' ) );
        }

        /**
         * Register a rewrite endpoint for the API.
         */
        function prefix__init() {
            // add tags with `_` prefix to avoid screwing up query
            add_rewrite_tag( '%_api_action%', '([a-zA-Z\d\-_+]+)' );

            // create URL rewrite
            add_rewrite_rule( '^api/([a-zA-Z\d\-_+]+)/?', 'index.php?_api_action=$matches[1]', 'top' );

            // required once after rules added/changed
            flush_rewrite_rules( true );
        }

        /**
         * Handle data (maybe) passed to the API endpoint.
         *
         * @param $query
         */
        function prefix__pre_get_posts( $query ) {

            if ( isset( $query->query_vars[ '_api_action' ] ) ) {

                switch ( $query->query_vars[ '_api_action' ] ) {
                    case 'random-banner';
                        $this->prefix__show_random_image();
                        break;
                }

                // kill the request on an API action call
                die();
            }
        }

        /**
         * Show random image
         *
         * @see http://example.com/api/random-banner/
         */
        function prefix__show_random_image() {
            $image_ids = get_posts( array (
                'post_type'      => 'attachment',
                'post_mime_type' => 'image',
                'post_status'    => 'inherit',
                'numberposts'    => 1,
                'orderby'        => 'rand',
                'fields'         => 'ids',
            ) );

            // convert ids to urls
            // $images = array_map( "wp_get_attachment_url", $image_ids );

            // convert ids to paths
            $images = array_map( "get_attached_file", $image_ids );

            $image_id   = $image_ids[ 0 ];
            $image_path = $images[ 0 ];

            // make sure url is readable -- if not, stop!
            if ( ! is_readable( $image_path ) ) {
                wp_die( "File is not readable: $image_path" );
            }

            $image = file_get_contents( $image_path );
            $type  = get_post_mime_type( $image_id );
            if ( empty ( $type ) ) {
                $type = "image/jpg";
            }

            // output headers and image data

            nocache_headers();
            header( "Content-type: $type;" );
            header( "Content-Length: " . strlen( $image ) );

            echo $image;
            die();
        }

    }

    // create api instance
    $api = new Prefix_API();

    // initialize the api hooks
    $api();
}

REST API

<img src="http://example.com/wp-json/prefix/v1/random-image/">

This version uses a custom REST API route.

/**
 * Register the REST route.
 * 
 * @see http://example.com/wp-json/prefix/v1/random-image/ 
 */
add_action( 'rest_api_init', function () {
    register_rest_route( 'prefix/v1', '/random-image/', array(
        'methods' => 'GET, POST',
        'callback' => 'prefix__show_random_image',
        'show_in_index' => false,
    ) );
} );

/**
 * Show random image
 */
function prefix__show_random_image(){
    $image_ids = get_posts(
        array(
            'post_type'      => 'attachment',
            'post_mime_type' => 'image',
            'post_status'    => 'inherit',
            'numberposts'    => 1,
            'orderby'        => 'rand',
            'fields'         => 'ids',
        ) );

    // convert ids to urls
    // $images = array_map( "wp_get_attachment_url", $image_ids );

    // convert ids to paths
    $images = array_map( "get_attached_file", $image_ids );

    $image_id   = $image_ids[ 0 ];
    $image_path = $images[ 0 ];

    // make sure url is readable -- if not, stop!
    if ( ! is_readable( $image_path ) ) {
        wp_die( "File is not readable: $image_path" );
    }

    $image = file_get_contents( $image_path );
    $type  = get_post_mime_type( $image_id );
    if ( empty ( $type ) ) {
        $type = "image/jpg";
    }

    // output headers and image data

    nocache_headers();
    header( "Content-type: $type;" );
    header( "Content-Length: " . strlen( $image ) );

    echo $image;
    die();
}
10
  • the typo was an accident when I replaced my real url with the example url. This still displays a broken image icon. Jan 20 '16 at 22:04
  • Try this version. It should tell you if the file is readable or not in the output. Just access it directly first.
    – jgraup
    Jan 20 '16 at 22:13
  • I updated to your new code but no change. How should it "tell" me if the file is unreadable? Jan 20 '16 at 22:17
  • 1
    Many thanks for your help, and the idea to leverage an endpoint vs an ajax url. Much cleaner. Jan 25 '16 at 16:49
  • 1
    @Jevuska - 2 more versions added. Take your pick.
    – jgraup
    Nov 21 '16 at 1:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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