0

Without using a plugin I would like to have a big background image changing on every click/load (or later on maybe every hour). So, I created a random_img.php file and put some code into header.php. Do not wonder about that header code! It is neccessary because some browsers (Safari, Chrome) otherwise do not accept background image changes because of caching purposes.

random_img.php:

<?php
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache"); // HTTP/1.0
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
header('Content-Type: image/jpeg');
$bilder = glob( "../is/images/*.jpg" );
shuffle( $bilder );
$zufall = imagecreatefromjpeg($bilder[0]);
imagejpeg($zufall); 
?>

head of header.php:

<?php echo '<style type="text/css"> 
  body {background: url(http://www.xxx.de/wp-content/themes/is/random_img.php?'.rand().') no-repeat center center fixed; -webkit-background-size: cover; -moz-background-size: cover; -o-background-size: cover; background-size: cover;}
</style>'; ?>

This is working so far, but I have some problems/questions:

  1. Right now I have declared a certain location for images with $bilder = glob( "../is/images/*.jpg" );, but this is bad, because once more I have to do something, meaning I have to upload pictures there. Instead I want to use a certain format/size, which I have defined before with add_image_size( 'hintergrundbild', 1500, 1500 ); in functions.php. How to do/connect that?

  2. Is there a cleaner way to do that instead of putting that line above into the head of header.php? I have a feeling, something is wrong about that, BUT on the other hand I could not find a solution for the caching problems with Safari and Chrome.

  3. Instead on loading a new picture EVERY click/load, how to code it to change automatically every full hour or so? I think, that might be nicer and less aggressive.

Thank you very much in advance, guys.

2

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' / '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.

  • First, thank you very much for this huge reply. Unfortunately, your solution has one problem. My goal (or wish) was to have everything automated without having anything to do, when uploading more pictures. In your proposal I would have to go through all 500 pictures and set that mark manually. I thought, that would be more easy to handle by recognising the already given slug (in my case "hintergrundbild"). Or did I understand something wrong? – vega Apr 19 '14 at 20:07
  • @vega the slug is not important, you can change it as you want. If you want to use add_image_size your images must be loaded as WordPress attachments, and you also need a way to recognize them among all other images.. you can probably use file name, for a more automated recognization, but then you are forced to name all images in same way... I think that the meta field method I used is more flexible and elegant, and if your problem is open 500 images one by one you can implement a way to add the meta field in a bulk way. I'm editing the answer to implement that. – gmazzap Apr 19 '14 at 20:39
  • Great, thank you very much. I will try everything then after your edit. – vega Apr 19 '14 at 21:07
  • @vega, adding bulk for uploads is harder than I recall... Sorry, but I'm afraid have no time to implement that. You can see how I implemented it in this plugin github.com/Giuseppe-Mazzapica/GMMediaTags There the bulk assignment is for terms, you should only assign a meta field. That require some javascript + a couple of ajax actions... – gmazzap Apr 19 '14 at 22:23

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.