Skip to main content
Easily create better & faster websites with the Total WordPress Theme Learn More
(opens a new tab)

How to Show a Different Featured Image for Mobile in WordPress

WordPress has a built-in function for displaying different sized images at different browser widths (responsive images). But what if you wanted to display a completely different image for different screen sizes as opposed to simply displaying a cropped version of the same image?

This guide will show you how to create a custom field for defining an alternative featured image for your posts and then display them at a specific breakpoint instead of the default image. So you can have one image show up for larger screens and a completely different image for smaller screens.

If you are not a developer you may want to consider using a plugin instead (I wasn’t able to locate any plugin for this). And if you are using our Total theme you don’t need to use code as it can be done via a dynamic template, reach out for support via the ThemeForest comments if you aren’t sure how to do that.

Important: This guide is specifically intended for themes using the core the_post_thumbnail() function. In other words, it’s intended for “classic” themes and will not work with block themes.

Create the WPEX_Mobile_Thumbnails Class

First we’ll create a new PHP class which will contain all of our code. We could write multiple functions but I prefer working with a single class so that we can keep our code contained in a single place.

class WPEX_Mobile_Thumbnails {

	/**
	 * Class constructor.
	 */
	public function __construct() {
		// Hook functions will go here (add_action/add_filter)
	}

	// Class methods (functions) will go here.

}
new WPEX_Mobile_Thumbnails;

Add a Mobile Image Custom Field

With our class in place we’ll go a head and add the code to create a new field in the post editor where you can define your “Mobile image”. Now, if you are already using a plugin like Advanced Custom Fields you can skip this part entirely and use the plugin instead for the field.

To add new fields we first need to hook into add_meta_boxes to define our new metabox. Start by adding the following code inside the class __construct() function:

add_action( 'add_meta_boxes', [ $this, 'add_meta_boxes' ] );

Then we’ll add our add_meta_boxes function after the constructor where it says “// Class methods (functions) will go here.” which will look as follows:

/**
 * Register the Mobile Image metabox.
 */
public function add_meta_box() {
	add_meta_box(
		'wpex-mobile-image',
		__( 'Mobile Image', 'text_domain' ),
		[ $this, 'display_meta_box' ],
		[ 'post' ],
		'advanced',
		'high'
	);
}

With this code added if you were to try loading a post you should see the new “Mobile Image” metabox below the post editor but it will display an error because we need to add the display_meta_box callback function which will display our custom field. To do this, add the following function following the previous code:

/**
 * Renders the Mobile Image metabox.
 */
public function display_meta_box( $post ) {
	wp_nonce_field(
		'wpex_mobile_image_metabox',
		'wpex_mobile_image_meta_nonce'
	);

	$mobile_image = get_post_meta( $post->ID, 'wpex_mobile_image', true );

	wp_enqueue_script(
		'wpex-mobile-image-metabox',
		trailingslashit( get_stylesheet_directory_uri() ) . 'assets/js/mobile-image-metabox.js',
		[],
		'1.0',
		true
	);

	?>

	<div class="wpex-mobile-image-metabox">
		<table class="form-table">
			<tr>
				<th>
					<label for="wpex-mobile-image-input"><?php esc_html_e( 'Image', 'text_domain' ); ?></label>
				</th>
				<td>
					<input id="wpex-mobile-image-input" name="wpex_mobile_image" type="text" value="<?php echo esc_attr( $mobile_image ); ?>">
				</td>
			</tr>
		</table>
	</div>

<?php }

If you’ve been following up to this point you should now be able to go to a post and view your custom field like the following screenshot.

Saving the New Custom Field Data

We have a nice new field we can use for our mobile thumbnail but if you try adding a value to the field and save your post nothing is going to happen. This is because WordPress doesn’t automatically save fields, we have to add our own saving logic.

Let’s add another action function to the class __construct function.

add_action( 'save_post', [ $this, 'save_meta_box' ] );

Now lets add our save_metabox function after the display_meta_box function (aka at the bottom of our class before the closing bracket.

/**
 * Save the Mobile Image metabox fields.
 */
public function save_meta_box( $post_id ) {

	// If this is an autosave, our form has not been submitted, so we don't want to do anything.
	if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
		return;
	}

	// Verify our nonce and that our custom field exists in the $_POST array.
	if ( ! array_key_exists( 'wpex_mobile_image_meta_nonce', $_POST )
		|| ! array_key_exists( 'wpex_mobile_image', $_POST )
		|| ! wp_verify_nonce( $_POST[ 'wpex_mobile_image_meta_nonce' ], 'wpex_mobile_image_metabox' )
	) {
		return;
	}

	// Check the user's permissions for security reasons.
	if ( array_key_exists( 'post_type', $_POST ) && 'page' === $_POST[ 'post_type' ] ) {
		if ( ! current_user_can( 'edit_page', $post_id ) ) {
			return;
		}
	} else {
		if ( ! current_user_can( 'edit_post', $post_id ) ) {
			return;
		}
	}

	// OK, it's safe for us to save the data now.
	$mobile_image = $_POST[ 'wpex_mobile_image' ];

	if ( $mobile_image ) {
		update_post_meta( $post_id, 'wpex_mobile_image', sanitize_text_field( $mobile_image ) );
	} else {
		delete_post_meta( $post_id, $field_id );
	}

}

With this code in place you should now be able to save the new Mobile Image field.

Adding an Image Select Button to Our Field

Having a field is great, but it’s not very useful if we have to go looking manually for our image in the media library so to make things easier we’re going to add a “Select Image” button below our field. The button will allow you to open the media library choose an image and add the image ID to the Mobile Image field.

Image Select Javascript

For this step you’ll need to create a new javascript file and add it to your theme or plugin (wherever you are adding your code). For the purpose of this guide I’m going to assume you’ve named your javascript file mobile-image-metabox.js and placed it inside a child theme at assets/js/mobile-image-metabox.js.

Inside the javascript file add the following code:

( function() {
	const button = document.querySelector( '.wpex-mobile-image-select' );
	const field = document.querySelector( '#wpex-mobile-image-input' );

	const onButtonClick = ( event ) => {
		event.preventDefault();

		let send_attachment_bkp = wp.media.editor.send.attachment;
		const currentImage = field.value;

		const customUploader = wp.media( {
			multiple: false
		} ).on( 'select', function() {
			const attachment = customUploader.state().get( 'selection' ).first().toJSON();
			field.value = attachment.id;
		} );

		customUploader.on( 'open', function() {
			if ( currentImage ) {
				const selection = customUploader.state().get( 'selection' )
				attachment = wp.media.attachment( currentImage );
				attachment.fetch();
				selection.add( attachment ? [attachment] : [] );
			}
		} );

		customUploader.open();
	};

	if ( button ) {
		button.addEventListener( 'click', onButtonClick );
	}
} )();

This script will handle the on click event event for the button we’ll add below our input field. This way we have an easy way to select an image and automatically add the image ID to our custom field.

Load the Javascript File

Our javascript file is basically useless unless we add a button and we load the script in the backend. To do this we’ll first use the core wp_enqueue_script function to load the script. Place the following code inside the display_meta_box function. It doesn’t matter where the code is added as long as it’s inside PHP tags. I will be placing it right after the line that reads:

$mobile_image = get_post_meta( $post->ID, 'wpex_mobile_image', true );

The code:

wp_enqueue_script(
	'wpex-mobile-image-metabox',
	trailingslashit( get_stylesheet_directory_uri() ) . 'assets/js/mobile-image-metabox.js',
	[],
	'1.0',
	true
);

Again, this code assumes you have placed your mobile-image-metabox.js file inside a child theme inside an assets/js/ folder. If you are adding your code inside a parent theme or plugin make sure to change the get_stylesheet_directory_uri() function with the proper alternative.

Add the Select Image Button

Now let’s add a button after our input. Place the following code inside the display_meta_box() function after the <input> element.

<button class="wpex-mobile-image-select"><?php esc_html_e( 'Select Image', 'text_domain' ); ?></button>

Now go a head and try it out! You should now see a button below the field that when clicked will open the media library popup so you can select your image and add it to the field.

Displaying the Mobile Image

Finally, we finished adding the meta box so that you can define your Mobile Images, next is to actually make things work on the front-end. There are two methods you can use to display the mobile image instead of the featured image.

Method 1: Hook into wp_get_attachment_image_attributes

The first method would be to hook into the wp_get_attachment_image_attributes filter to alter the image attributes “on-the-fly”. This may be what you choose to do if you are writing a custom plugin or using a child theme and don’t have access to the theme files where the images are displayed.

Let’s add a new function to the class _construct.

add_filter( 'wp_get_attachment_image_attributes', [ $this, 'attachment_image_attributes' ], 10, 3 );

Next add the function that hooks into this filter at the bottom of the class after the last function you added:

/**
 * Filters the image attachment attributes.
 */
public function attachment_image_attributes( $attr, $attachment, $size ) {
	if ( 'IMAGE_SIZE_TO_TARGET' === $size ) {
		$mobile_image = get_post_meta( get_the_ID(), 'wpex_mobile_image', true );
		if ( $mobile_image ) {
			$mobile_image_url = wp_get_attachment_image_url( $mobile_image, 'full' );
			if ( $mobile_image_url ) {
				$attr['sizes'] = '(max-width: 640px) 640px';
				$attr['srcset'] = $mobile_image_url . ' 640w,' . $attr['src'];
			}
		}
	}
	return $attr;
}

This function will need to be modified to fit your needs. You will need to change where it says IMAGE_SIZE_TO_TARGET to be the name of the image size you want to target. And you will also need to change the 640px and 640w values to match the breakpoint you want to target.

Method 2: Using the_post_thumbnail()

If you have access to the code used to display the thumbnails which should be using either the_post_thumbnail or get_the_post_thumbnail then what you can do instead is update the function to pass on custom attributes. Example:

$post_id = get_the_ID();
$mobile_image = get_post_meta( $post_id, 'wpex_mobile_image', true );
$mobile_image_url = wp_get_attachment_image_url( $mobile_image, 'full' );

$attrs = [];

if ( $mobile_image_url ) {
	$attr['sizes'] = '(max-width: 640px) 640px';
	$attr['srcset'] = $mobile_image_url . ' 640w,' . get_the_post_thumbnail_url( $post_id, 'full' );
}

the_post_thumbnail( 'full', $attrs );

Wrapping Up

To make sure you followed the guide correctly you can view the full PHP class code on gist here and the full javascript code here.

Lastly, if you are having any issues make sure that you are testing using a mobile device or the browser developer tools. One thing that may be confusing is if you load the site on desktop and then shrink your browser you won’t see the mobile image. This is because the browser has already loaded what it considers to be the “optimal” image so it won’t swap to the smaller version thus preventing extra server requests.

You’ll need to load up the site on a small screen to make sure everything is working as expected. If you have any questions let me know in the comments!

16 Comments
  1. Jinson Abraham · 12 years ago

    Its a smart trick AJ. Nice one.
    cheers

    • AJ Clarke | WPExplorer · 12 years ago

      Nice to see you around here. We love your work 😉

  2. beyondtime · 12 years ago

    I love to click pics and then edit in various ways. This tutorial is pretty interesting will try this out soon.

  3. Colin Crawford · 12 years ago

    Excellent tutorial AJ, so simple when you know how.

  4. Adam · 12 years ago

    I would think that using wp_is_mobile ( http://codex.wordpress.org/Function_Reference/wp_is_mobile ) would be an alternative (or better?) to using “Mobile Detect”. Nice technique for mobile devices!

    • AJ Clarke | WPExplorer · 12 years ago

      You are correct and I should have mentioned it. The only reason I like to use this specific script is because it’s a lot more extended. For simple solutions wp_is_mobile() does a great job though.

      Thanks for stopping by Adam!

  5. Ale Montemayor · 11 years ago

    Hi AJ!

    Do you think this script would work if images are on a background slide show?
    I purchased a theme that claimed to be responsive, and images looked cropped when you browse the site from smartphones or tablets.

    Website is this:

    siie.com.mx/Wordpress

    It looks like this on iPhone:

    rubikmedia.com/siie.png

    Thanks for your insight!

    Greetings from Mexico.

    • AJ Clarke | WPExplorer · 11 years ago

      No, that is something completely different. Your theme is actually using a script called Supersized, if you have a look at the documentation there are options to keep the images proportional as your screen size gets smaller – you should contact the author of the theme to help you fix the issue.

  6. Chris Borgman · 10 years ago

    Hi AJ,
    I’m actually wanting to add some CSS for just mobile devices, could you suggest how to do that?

    I tried this in my functions:

    if ($detect->isMobile()) {
    echo ;
    }
    

    …but I got this in return:

    Parse error: syntax error, unexpected ‘<' in /home/profolio/public_html/wp-content/uploads/sites/12/dynamik-gen/theme/custom-functions.php on line 6

    I only need to a couple of lines target to mobile, is there a way to write it inline instead of ref an external CSS file?

    Thank!!

    • AJ Clarke · 10 years ago

      Yep the code above is broken. You can actually use wp_is_mobile() to check for mobile devices, however, this function doesn’t always play nicely with caching plugins/functions – https://codex.wordpress.org/Function_Reference/wp_is_mobile

      if ( wp_is_mobile() {
      // do things here
      }
      

      ps: This post is a bit old…otherwise I would have recommended using the same thing as I just posted in the comment above.

  7. Michael Fox · 2 years ago

    Hi AJ,

    This is a great piece of code. Have it functioning on our staging site but was wondering if there is a quick way to extend it to pages as well. Not quite sure how to go about adding it. Any pointers would be appreciated.

    • AJ Clarke · 1 year ago

      To add the field to pages all you need to do is modify the “add_meta_box” function so where it says [ 'post' ] it includes pages as well [ 'post', 'page' ].

  8. Michael Fox · 1 year ago

    Thanks for this useful piece of code. Using it on our site. Just wondering if there was a way to show a preview of the image selected in the admin panel above the input field for the image ID?

    • AJ Clarke · 1 year ago

      Of course it’s possible! I decided against doing this because it requires extra javascript to modify the image when changing it and I like keeping my code as fast and a slim as possible. Now, if you are fine just showing the image and it doesn’t get replaced until saving the post you can easily modify the code a bit to make it work. Simply add the following code above the input:

      if ( $mobile_image ) {
      	echo wp_get_attachment_image( $mobile_image, 'full' );
      }
      

      Make sure to add the opening an closing PHP tags (I can’t put that in the snippet because it will break my comment).

  9. Emily F · 7 months ago

    This is a beautiful and thorough solution but is much more than I need. I would like to leave all my featured images in place for desktop users and use just one single image from the media library as the featured image for mobile renditions of my posts and pages. I don’t need the ability to select a different mobile image for each page/post. Is there a short bit of code to do that? This may sound like an odd thing to do, but my theme handles the header image poorly, so I have used the feature image as the header image on all posts/pages and I have about 1200 of them. It would be easiest just to default to a small image of my logo as the featured image for mobile users rather than go through all those posts/pages and create a special mobile image for each one. Thank you very much.

    • AJ Clarke · 1 month ago

      This should be very easy to do but it really depends on your theme. For example if you are using our Total theme which allows you to create dynamic templates for your posts you can simply insert 2 image elements so the first displays the featured image and the second displays your mobile image then use the visibility options to show/hide them accordingly. If your theme uses a builder as well, then this would be the recommended solution (insert 2 images and have each displayed when wanted). If you are using a theme where your post display is hard set in the template then you will need custom code and the solution really depends on the theme. Most likely you will want to create a child theme and override the post template so you can insert your mobile image after your featured image, then use CSS to show/hide them accordingly.

Leave a Reply

Your email address will not be published. Required fields are marked *

Learn how your comment data is processed by viewing our privacy policy here.