Random background image showing on website per click/load

If you want to use add_image_size, your images must be uploaded as WordPress attachments, and not only be present inside a specific folder.

So first of all register your custom size:

add_action( 'after_setup_theme', 'gmrb_background_image_size' );

function gmrb_background_image_size() {
  // using WP 3.9 crop position
  // see https://codex.wordpress.org/Function_Reference/add_image_size#Crop_Mode
  add_image_size( 'gmrb_background', 1500, 1500, array( 'center', 'center') );
}

After that, go in your backend and upload all your background images, going to Media > Add New screen.

Now the problem is how to recognize which images are backgrounds and which not among all the picture updated?

I think a good idea is to use a meta field '_is_background' and set it to true for background images.

Since WP 3.5 exists an hook 'attachment_submitbox_misc_actions' that allow add some output one the ‘Save”https://wordpress.stackexchange.com/”Update’ metabox for attachments.
So you can use that hook to output a checkbox, and then use 'update_post_meta' hook to save the checkbox value as post custom field.

Show the field:

add_action( 'attachment_submitbox_misc_actions', 'gmrb_background_support' );

function gmrb_background_checkbox() {
  wp_nonce_field('is_background', '_is_bkgrnd_n');
  $html="<div class="misc-pub-section misc-pub-filename"><label for="is_bkgrnd">";
  $html .= '<input id="is_bkgrnd" name="_is_background" type="checkbox" value="1"%s />';
  $html .= '&nbsp;%s</label></div>';
  global $post;
  $is = get_post_meta($post->ID, '_is_background', TRUE );
  printf( $html , checked(1, $is, FALSE), esc_html__('Is Background?', 'your-txt-domain') );
}

Save the field:

add_action( 'update_post_meta', 'gmrb_background_checkbox_save', 20, 4 );

function gmrb_background_checkbox_save( $mid, $pid, $key, $value ) {
  $post = filter_input(INPUT_SERVER, 'REQUEST_METHOD', FILTER_SANITIZE_STRING);
  if ( strtoupper($post) !== 'POST' ) return;
  if ( ! $key === '_wp_attachment_metadata') return;
  if ( ! check_admin_referer('is_background', '_is_bkgrnd_n') ) return;
  $is = (int) filter_input(INPUT_POST, '_is_background', FILTER_SANITIZE_NUMBER_INT);
  if ( $is === 1 ) {
    update_post_meta($pid, '_is_background', '1' );
  } elseif( get_post_meta($pid, '_is_background', TRUE ) ) {
    delete_post_meta($pid, '_is_background');
  }
}

Output of code above in attachment edit screen:

Checkbox for attachment custom field

So, after having uploaded some background images, edit them and check the ‘Is thumbnail’ checkbox.

Now what you need is a way to randomly get an image, and change it every hour.

Once backgrounds are attachment posts, we can use get_posts to do the trickin combination with a transient to change result hourly.

function gmrb_background_get_random() {
  // first check transient
  $background = get_transient( 'my_background_random' );
  if ( empty( $background ) ) {
    // no transient, perform a query
    $args = array(
      'post_type' => 'attachment',
      'post_status' => 'inherit',
      'orderby' => 'rand',
      'posts_per_page' => 1,
      'meta_query' => array(
        array( 'key' => '_is_background', 'value' => 1, 'type' => 'NUMERIC' )
      )
    );
    $result = (array) get_posts( $args );
    if ( ! empty( $result ) ) {
      $attachment = array_shift( $result );
      $image =  wp_get_attachment_image_src( $attachment->ID, 'gmrb_background' );
      $background = ! empty( $image ) ? $image[0] : FALSE;
      if ( $background ) {
        // save transient for one hour
        set_transient( 'my_background_random', $background, HOUR_IN_SECONDS );
      }
    }
  }
  return $background;
}

Last thing left undone, is use this random image as background.

I suggest you to implement the custom background feature, in this way, using core interface you can define an image to be used as default, also the feature add the class ‘custom-background’ to body classes and handle the inline style addition needed to use the custom image as backgroud. (See Codex pages linked above for more info).

This save you some work, and give an interface to additional background properties, like repeat-x and repeat-y, position, scroll or fixed…

The only thing you need to do, is to use the 'theme_mod_background_image' filter hook to return a random image (retrieved using my_background_get_random() above) instead of the image set in the core interface, that can be used as fallback if my_background_get_random() for any reason return false (e.g. wen no images are set as background).

First let’s add support for custom background

add_action( 'after_setup_theme', 'gmrb_background_support' );

function gmrb_background_support() {
  if ( ! current_theme_supports( 'custom-background' ) ) {
    add_theme_support( 'custom-background' );
  }
}

Now let’s filter the image used by custom background feature:

add_filter( 'theme_mod_background_image', 'gmrb_background_custom_filter' );

function gmrb_background_custom_filter( $image ) {
  // do nothing on admin or core custom background interface will not work properly
  if ( is_admin() ) return $image;
  $random = gmrb_background_get_random();
  if ( $random && filter_var( $random, FILTER_VALIDATE_URL ) ) {
    $image = $random;
  }
  return $image;
}

We are done. You have only to be sure that inside your templates (usually inside header.php) there a call to wp_head() and the body html tag contain body_class().
Something like:

<body <?php body_class(); ?>>

Consider that both are best practices and should be done in all WordPress themes no matter if the custom background feature is implemented or not.


All the code is available as plugin in a Gist here.