1

How can I set a post's featured image using the content of a shortcode? For instance, the following shortcode should set the post's featured image to the image at www.google.de/nicepic.jpg:

[post_image]www.google.de/nicepic.jpg[/post_image]

2 Answers 2

1

The Shortcode API is more geared for altering post content rather than performing actions in response to content, and as such tend to require more creativity to alter other post data - though it can still be done. Ultimately, using a shortcode to set a featured image is kind of bizarre considering that you can do the same thing by clicking a button in the post editor UI.

I emphasize that my solutions below are untested hacks that rely on using WordPress components in non-standard ways


Solution

Use the Plugin API to write a plugin that uses the Shortcode API to register your shortcode.

In order to set a remote image as the featured image, you'll need to download the image, move it to a permanent location (such as wp-content/uploads), attach it to the post, then set the featured image. There are a few ways to accomplish this, but I think the most straightforward would be to

  1. Use download_url() to download the remote image to the temporary directory.
  2. Pass the temporary filepath to handle_media_sideload() to move the file to wp-content/uploads, generate attachment metadata, and attach it to the post.
  3. Pass the returned attachment ID to set_post_thumbnail() to specify it as the featured image.

The tricky part about applying the above in a shortcode's callback function is that handle_media_sideload() and set_post_thumbnail() both require the post's ID, and shortcode callbacks are not passed the post ID nor the post object itself. The have access to this data when shortcodes are applied to posts getting displayed in The Loop by way of the global $post object, however applying the above operation at that point could result in the image being downloaded and set every time the post was displayed.

One possible work-around to achieve the hack would be to use a class property to pass the post ID, and return early from the shortcode callback the shortcode's contents weren't modified.


Alternate Solution

A simpler hack may be to manually extract the remote image URL from the post's contents on an action hook that fires when a post is saved (such as save_post). A shortcode could still be registered to return a blank string. Something along the lines of

$featured_image_shortcode = 'post_image';

wpse_211802_featured_image_shortcode( $atts, $content ) {
  return '';
}

add_shortcode( $featured_image_shortcode, 'wpse_211802_featured_image_shortcode' );

wpse_211802_featured_image_from_shortcode_url( $post_id ) {
  $content           = get_the_content( $post_id );
  $shortcode_matches = array();
  
  if( ! has_shortcode( $content, 'post_image' ) )
    return;
  
  preg_match_all( '\[' . $featured_image_shortcode . '\](.*)\[\/' . $featured_image_shortcode . '\]', $content, $shortcode_matches );
  
  $url      = $shortcode_matches[ 1 ][ 0 ];
  $tempfile = download_url( $url );
  
  if( is_wp_error( $tempfile ) ){
    // download failed, handle error
    return;
  }

  // Set variables for storage
  preg_match( '/[^\?]+\.(jpg|jpe|jpeg|gif|png)/i', $url, $matches );

  $desc       = 'Featured Image for Post ' . $post_id;
  $file_array = array(
    'name'     => basename( $matches[0] ),
    'tmp_name' => $tempfile
  );

  // Sideload the downloaded file as an attachment to this post
  $attachment_id = media_handle_sideload( $file_array, $post_id, $desc );

  // If errors encountered while sideloading, delete the downloaded file
  if ( is_wp_error( $attachment_id ) ) {
    @unlink( $tempfile );
    return;
  }
  
  // If all went well, set the featured image
  set_post_thumbnail( $post_id, $attachment_id );
}

add_action( 'save_post', 'wpse_211802_featured_image_from_shortcode_url' );

You may need to require_once() additional files in order for the above to function. If you do something similar, I'd recommend expanding upon the error handling and URL validation.

Still though - far easier to just set the featured image with the button on the post editor UI.

3
  • I tried this - but it is not working. I don't know why - but not a single image upload from url sample is working. My own function based on the wordpress.com sample is also not working... Commented Dec 16, 2015 at 23:51
  • Hey, it's just an idea - didn't say it would work exactly as I wrote it ;) . But the general approach should yield a solution. You can always try to troubleshoot it. Or implement it the way I suggested as the first solution. I'm not sure what "the wordpress.com sample" is, but the WordPress Development community doesn't tend to have much to do with wordpress.com - it's mostly a Q&A site for the self-hosted WordPress installations of the WordPress project at wordpress.org. Commented Dec 17, 2015 at 2:10
  • Thank you for your help. Now I have a working prototype. Commented Dec 18, 2015 at 10:47
0

Not a full answer, but maybe a hint in the right direction...

In terms of saved data, a featured image is actually a custom field named _thumbnail_id that holds the numeric ID of the image attachment.

When exporting your posts as XML, it shows up like this:

<wp:postmeta>
  <wp:meta_key>_thumbnail_id</wp:meta_key>
  <wp:meta_value><![CDATA[1497]]></wp:meta_value>
</wp:postmeta>`

So you could try to add images programmatically by using add_post_meta().

Using external image URLs won't be that easy though, as WordPress doesn't allow them for Featured Images.

2
  • Ohh ... I see. In this case I think I should add the image to my wordpress media library?! But I think this is not that easy.... Commented Dec 14, 2015 at 21:36
  • Indeed probably not that easy... I would opt for an easier workaround, such as (1) just adding the image URL to your own custom field, and (2) tweaking your theme so that it gets displayed the same way as the featured image would. Commented Dec 14, 2015 at 21:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.