Featued Image (Post_thumbnail)
-
First of all thanks for this great plugin! I have a question and I hope you can help me out. First I will try to explain the purpose for which I want to use this plugin.
The website I am working on will be filled with content by users. I don’t want the users to select featured images. (They will forget or give ‘ugly’ images). I want the featured images randomly picked based on categories I made.
So, if a user posts in category A, it will pick an image from category A and assign it as a post_thumbnail.
What I have so far (and I don’t know if I am on the right track or not)
In my single.php I have added the following code:$category_current = get_the_category(); echo do_shortcode('[mla_gallery category_name="'.$category_current[0]->name.'" columns=1 size=full order=date orderby=rand posts_per_page=1 link=none post_parent=all]');
It displays a random image based on the category. Is it possible to set the image as featured?
Thanks, Moniquehttps://www.ads-software.com/plugins/media-library-assistant/
-
Monique,
Thank you for your kind words and for this interesting question. You are on the right track, but there are a few different ways to interpret your question “Is it possible to set the image as featured?”
The WordPress Featured Image (also called the Post Thumbnail) is stored as an entry in the
postmeta
database table. Themeta_key
is “_thumbnail_id” and themeta_value
is the “Post ID” of the Media Library image you want to be displayed. The theme will take care of position the image and selecting the appropriate size, etc. Somewhere in yoursingle.php
file you should find something like< ?php the_post_thumbnail(); ? >
, which calls the WordPress function that displays the thumbnail image.So, there are at least two things you can do. First, you can replace the function call with your
echo do_shortcode( [mla_gallery ...
code. That would replace the thumbnail image with your random image. Second, you could change the database entry, updating the Post ID of the Featured Image and then letting the WordPress function do its work.The first alternative is somewhat simpler, but the second alternative preserves whatever position and display choices your theme has coded.
If you want the second alternative, then you have a further choice to make: 1) you could update the database once when the post/page content is created, or 2) you could update the database each time the post/page is displayed.
If you can tell me your answers to those questions I can help you with a more specific solution. If you can post more of the code from your
single.php
file that would be helpful as well.Thanks for your interest any any further details you can supply.
Hello David,
Thank you very much for your answer. As I have seen on the plugin support page, you take a lot of time helping people out, wonderfull (rated 5 stars)
I have read your answer and I think the best solution would be to update the database once when the post/page is created.
If I choose for the first option, then it will not display the post_thumbnail on my listing pages (Don’t know how to say it, but I mean the page
which shows all the post-excerpts of the specific category), so I have to alter code on different places.I have allready looked up where the post_thumbnail is loaded, and it happends in the core file of my theme (valenti)
Here is the code of my single.php
<article id="post-<?php the_ID(); ?>" <?php post_class('clearfix'); ?> role="article" <?php if ( $cb_review_checkbox != '1' ) { echo 'itemscope itemtype="https://schema.org/BlogPosting"'; } ?>> <?php if ( ( $cb_featured_image_style == 'off' ) && ( $cb_breadcrumbs != 'off' ) ) { echo cb_breadcrumbs( 'padding-off' ); } if ( ( $cb_featured_image_style == 'standard' ) && ( $cb_post_format != 'gallery' ) ) { echo cb_featured_image( $post, 'standard' ); } if ( ( $cb_featured_image_style == 'off' ) || ( $cb_post_format == 'gallery' ) ) { echo cb_featured_image( $post, 'off' ); } ?> <section class="entry-content clearfix" <?php if ( $cb_review_checkbox == '1' ) { echo 'itemprop="reviewBody"'; } else { echo 'itemprop="articleBody"'; } ?>> <?php the_content(); ?> </section> <!-- end article section -->
The code from core file of my theme:
/********************* FEATURED IMAGE THUMBNAILS *********************/ if ( ! function_exists( 'cb_thumbnail' ) ) { function cb_thumbnail($width, $height) { echo '<a href="'.get_permalink() .'">'; if (has_post_thumbnail()) { $cb_featured_image = the_post_thumbnail('cb-'.$width.'-'.$height); echo $cb_featured_image[0]; } else { $cb_thumbnail = get_template_directory_uri().'/library/images/thumbnail-'.$width.'x'.$height.'.png'; $cb_retina_thumbnail = get_template_directory_uri().'/library/images/thumbnail-'.$width.'x'.$height.'@2x.png'; echo '<img src="'. $cb_thumbnail .'" alt="article placeholder" data-src-retina="'. $cb_retina_thumbnail .'" data-src="'. $cb_thumbnail .'">'; } echo '</a>'; } }
and:
/********************* FEATURED IMAGE THUMBNAILS RETURN *********************/ if ( ! function_exists( 'cb_get_thumbnail' ) ) { function cb_get_thumbnail($width, $height, $cb_post_id) { $cb_output = '<a href="'. get_permalink($cb_post_id) .'">'; if ( has_post_thumbnail( $cb_post_id ) ) { $cb_featured_image = get_the_post_thumbnail( $cb_post_id, 'cb-'. $width. '-' . $height ); $cb_output .= $cb_featured_image; } else { $cb_thumbnail = get_template_directory_uri() .'/library/images/thumbnail-'. $width .'x'. $height .'.png'; $cb_retina_thumbnail = get_template_directory_uri() .'/library/images/thumbnail-'. $width .'x'. $height .'@2x.png'; $cb_output.= '<img src="'. $cb_thumbnail .'" alt="article placeholder" data-src-retina="'. $cb_retina_thumbnail .'" data-src="'. $cb_thumbnail .'">'; } $cb_output .= '</a>'; return $cb_output; } }
Thanks in advance for your answer.
Monique,
Thank you for taking the time to post a favorable review and rating – feedback like this is an important source of ideas and motivation to continue improving the plugin.
Thanks as well for adding some details to your question regarding automatic assignment of a post’s Featured Image. As I understand it, you’d like to permanently assign a Featured Image to each post as it is created. As you observed, this will preserve all of the logic in your theme for handling the Featured Image, such as displaying it on the “Category archive pages” (the WordPress term for what you referred to as the “listing pages”).
You’ve asked specifically about WordPress Categories, but I’m going to generalize the answer a bit so it will work for any taxonomy.
To implement this approach, you must write some code to:
- Pick one of the taxonomy terms assigned to the post
- Pick a random image from those assigned to the chosen taxonomy term
- Set the image as the Featured Image of the post
For step one your example used
get_the_category()
. I’m going to use the more generalget_the_terms()
because it will work with any taxonomy and anywhere in the site’s code provided you know the post ID. If there are multiple terms assigned I’ll take the first one, as you did. If there are no terms assigned I’ll take the site-wide default category (other taxonomies will require a different choice). Here’s the code for the first step:$the_terms = get_the_terms( $post_ID, $taxonomy ); if ( empty( $the_terms ) ) { $the_terms = array( get_term_by( 'id', get_option('default_category'), 'category') ); } $chosen_name = $the_terms[0]->name;
Step two is the most interesting; there are two different ways to proceed. Both ways start as you did by creating an
[mla_gallery]
shortcode that finds one image at random from all images assigned to the chosen taxonomy term. The shortcode must name the taxonomy and the term, then pick one random image usingorderby=rand posts_per_page=1
. Here’s the shortcode for that:do_shortcode( sprintf( '[mla_gallery %1$s="%2$s" orderby=rand posts_per_page=1]', $taxonomy, $chosen_name ) );
There are two ways to get from here to the third step. First, we can use the
mla_alt_shortcode
parameter to pass the image’s ID to another PHP function that sets the Featured Image. Second, we can catch the[mla_gallery]
output, parse out the image’s ID and use it to set the Featured Image.Here’s the first way:
do_shortcode( sprintf( '[mla_gallery %1$s="%2$s" orderby=rand posts_per_page=1 mla_alt_shortcode=random_featured_image rfi_post_id="%3$d"]', $taxonomy, $chosen_name, $post_ID ) );
I’ve added two parameters;
mla_alt_shortcode=random_featured_image
names another shortcode which is just a PHP function called in a particular way, andrfi_post_id="%3$d"
passes the post ID on to that second function. I’ll come back to to this “random_featured_image shortcode” way later.Here’s the second, somewhat simpler way:
$gallery = do_shortcode( sprintf( '[mla_gallery %1$s="%2$s" orderby=rand posts_per_page=1 size=none link=none mla_style=none mla_caption="rfi_image_id={+attachment_ID+}"]', $taxonomy, $chosen_name, $post_ID ) );
I’ve added three parameters (
size=none link=none mla_style=none
) to make the[mla_gallery]
output simpler and more compact. The last parameter,mla_caption="rfi_image_id={+attachment_ID+}"
adds the image’s ID to the gallery in a way that’s easy to parse out.The third step parses the image ID from the gallery and uses it to assign the Featured Image:
if ( preg_match( '/rfi_image_id=(\d+)/', $gallery, $matches ) ) { $success = set_post_thumbnail( $post_ID, absint( $matches[1] ) ); }
The
preg_match
function (part of PHP) looks in$gallery
for a pattern starting with “rfi_image_id=” and extracts the number that follows, storing it in$matches
. This is used in the function call that completes the job by assigning the image as the post’s Featured ID. Simple.There are a few more details (see below) but this is the essence of the solution. Now we have to find the right place to put our code so WordPress can call it when the post is created (or updated) and pass the $post_ID to it.
Your example added code to the
single.php
file, which is run when WordPress displays the post. Since you’ve decided to set the Featured Image when the post is created,single.php
is not the right place for the code. The WordPress Plugin API provides thesave_post
action, which is a great place to run the code. You can read up on the API and actions in the WordPress Codex.Here’s a function that ties all three steps together in one place, and a call that registers the function with WordPress so it can be called at the right time:
function rfi_save_post_action( $post_ID, $post, $update ) { /* * Only assign a random image if there is no current value. You can test the $update * argument if you want to only assign an image when the post is first created. */ if ( '' != get_the_post_thumbnail( $post_ID ) ) { return; } $taxonomy = 'category'; // or 'tag', 'attachment_category', 'attachment_tag', etc. /* * Use whatever logic you want to handle a post with no assigned terms */ $the_terms = get_the_terms( $post_ID, $taxonomy ); if ( empty( $the_terms ) ) { $the_terms = array( get_term_by( 'id', get_option('default_category'), 'category') ); } /* * Pick the term, e.g. the first value or perhaps a random value */ $chosen_name = $the_terms[0]->name; /* * Find the right [mla_gallery] parameter name for the WordPress taxonomies */ switch ( $taxonomy ) { case 'category': $taxonomy = 'category_name'; break; case 'post_tag': $taxonomy = 'tag'; break; default: // other taxonomies can be used as-is } /* * Compose a simple gallery and capture the output */ $gallery = do_shortcode( sprintf( '[mla_gallery %1$s="%2$s" orderby=rand posts_per_page=1 size=none link=none mla_style=none mla_caption="rfi_image_id={+attachment_ID+}"]', $taxonomy, $chosen_name, $post_ID ) ); /* * Find the ID of the random image, if there is one, * then set the featured image. */ if ( preg_match( '/rfi_image_id=(\d+)/', $gallery, $matches ) ) { $success = set_post_thumbnail( $post_ID, absint( $matches[1] ) ); } } add_action( 'save_post', 'rfi_save_post_action', 10, 3 );
The very last line registers the function as an action, gives it the default priority, and tells WordPress to pass the three arguments required by the function.
So, where does this function and registration call go? You could put it in your theme’s
functions.php
file. However, that file will be replaced each time the theme is updated. Many themes have some method for adding custom code; you can investigate that.As the Codex says, “You can produce the same results by adding code to a WordPress Plugin or through the WordPress Theme functions file.” Creating a simple plugin for the code isn’t all that difficult, and I have included a complete example “Random Featured Image” plugin at the bottom of this post. The plugin includes the “random_featured_image” shortcode I introduced earlier.
I hope the above code or the plugin below gives you what you need to accomplish your objective. I’m going to mark this issue resolved, but please update it if you have any problems or further questions. Thanks for you interest in the plugin and for an interesting application question.
The example custom plugin:
<?php /** * Provides two approaches for assigning a random "post thumbnail"/"featured image" to a post * * When a post is created or updated, an associated taxonomy term is selected and used to pick * a random image having the same term. The image is assigned as the "post thumbnail"/"featured image" * for the post. * * @package Random Featured Image * @version 1.00 */ /* Plugin Name: Random Featured Image Plugin URI: https://fairtradejudaica.org/media-library-assistant-a-wordpress-plugin/ Description: Assigns a random image as the "post thumbnail"/"featured image". Author: David Lingren Version: 1.00 Author URI: https://fairtradejudaica.org/our-story/staff/ */ /** * Class Random Featured Image implements two approaches for assigning a random * "post thumbnail"/"featured image": * * 1) A shortcode which takes as input the "ids" parameter from [mla_gallery mla_alt_shortcode=...] * 2) Code that parses the [mla_gallery] output to find the ID of the selected image. * * @package Random Featured Image * @since 1.00 */ class RandomFeaturedImage { /** * Select the approach: 1) (true) use the shortcode, 2) (false) parse the gallery */ const USE_SHORTCODE = false; //true; /** * Select the taxonomy, e.g., 'category', 'post_tag', 'attachment_category', 'attachment_tag' */ const TAXONOMY = 'category'; /** * Initialization function, similar to __construct() * * Installs an action for the WordPress 'save_post' hook. * * @since 1.00 * * @return void */ public static function initialize() { add_action( 'save_post', 'RandomFeaturedImage::rfi_save_post_action', 10, 3 ); } /** * WordPress Action; called from 'save_post' hook(s). * * Triggered by wp_insert_post and wp_publish_post in wp-includes/post.php * * @since 1.00 * * @param integer Post ID * @param object Post object * @param boolean Are we updating or creating? * * @return void */ public static function rfi_save_post_action( $post_ID, $post, $update ) { /* * Only assign a random image if there is no prior value. You can test the $update * argument if you want to only assign an image when the post is first created. */ if ( '' != get_the_post_thumbnail( $post_ID ) ) { return; } /* * Use whatever logic you want to handle a post with no assigned terms */ $the_terms = get_the_terms( $post_ID, self::TAXONOMY ); if ( empty( $the_terms ) ) { $the_terms = array( get_term_by( 'id', get_option('default_category'), 'category') ); } /* * Pick the term, e.g. the first value or perhaps a random value */ $chosen_name = $the_terms[0]->name; /* * Find the right [mla_gallery] parameter name for the taxonomy */ switch ( self::TAXONOMY ) { case 'category': $taxonomy = 'category_name'; break; case 'post_tag': $taxonomy = 'tag'; break; default: $taxonomy = self::TAXONOMY; } /* * Use a shortcode to finish the job, or parse the image ID our of gallery output */ if ( self::USE_SHORTCODE ) { add_shortcode( 'random_featured_image', 'RandomFeaturedImage::random_featured_image_shortcode' ); do_shortcode( sprintf( '[mla_gallery %1$s="%2$s" orderby=rand posts_per_page=1 mla_alt_shortcode=random_featured_image rfi_post_id="%3$d"]', $taxonomy, $chosen_name, $post_ID ) ); remove_shortcode( 'random_featured_image' ); } else { /* * Compose a simple gallery and capture the output */ $gallery = do_shortcode( sprintf( '[mla_gallery %1$s="%2$s" orderby=rand posts_per_page=1 size=none link=none mla_style=none mla_caption="rfi_image_id={+attachment_ID+}"]', $taxonomy, $chosen_name, $post_ID ) ); /* * Find the ID of the random image, if there is one, * then set the featured image. */ if ( preg_match( '/rfi_image_id=(\d+)/', $gallery, $matches ) ) { $success = set_post_thumbnail( $post_ID, absint( $matches[1] ) ); } } } /** * WordPress Shortcode; assigns the Featured Image * * @since 1.00 * * @param array shortcode parameters; defaults ( 'rfi_post_id' => 0, 'ids' => '' ) * * @return void echoes error messages, if any */ public static function random_featured_image_shortcode( $attr ) { $default_arguments = array( 'rfi_post_id' => 0, 'ids' => '', ); /* * Accept only the attributes we need and supply defaults */ $arguments = shortcode_atts( $default_arguments, $attr ); /* * Make sure we have a post ID */ if ( empty( $arguments['rfi_post_id'] ) ) { return ''; } /* * Make sure we have exactly one image ID */ $ids = ! empty ( $arguments['ids'] ) ? explode( ',', $arguments['ids'] ) : array(); if ( empty( $ids ) ) { return ''; } else { $ids = $ids[0]; } /* * At last! Set the new featured image */ $success = set_post_thumbnail( absint( $arguments['rfi_post_id'] ), absint( $ids ) ); return ''; } //random_featured_image_shortcode } //RandomFeaturedImage /* * Install the shortcode and/or filters at an early opportunity */ add_action('init', 'RandomFeaturedImage::initialize'); ?>
Hello David,
Thank you so much for taking the time and effort to help out. It is really amazing.
Also thank you for writing so much code. (I think this can be a very usefull add-on for the plugin)
But, there is a tiny problem ??
When posting a new post, the taxonomy for the category is ‘no category’. So it will pick a random image which has not been assigned for the specific category. On saving (even though I set the corect category, the image will still be a random image from the no-category)
(If I update the post, I have to delete the wrongly assigned (the no-category) featured image. If I save the post then the correct category image from selected the category is assigned.
So, the plugin does its job almost perfectly …
Sorry for the inconvenience!Thanks for the update and your test results; not an inconvenience at all.
I’ve made some changes reflecting what I think you’d like to see. One reason for the ‘no category’ assignment was that the ‘save_post’ hook is called when WordPress “auto saves” the draft as you create the post; I’ve eliminated that. The revised code below changes the logic so an image is only assigned to published posts that have been assigned at least one category other than the default category. You can make any other changes you need to get the results you want.
To make the changes in your code, replace everything from the beginning of the
rfi_save_post_action
function down to the$chosen_name = $the_terms[0]->name;
line that picks the term. The revised code is:function rfi_save_post_action( $post_ID, $post, $update ) { /* * Only assign a random image if (in this order): * 1) The post has been published (avoiding "auto save" revisions) * 2) The post has one or more terms assigned (but not the "default category") * 3) There is no current Featured Image */ if ( 'publish' != $post->post_status ) { return; } $the_terms = get_the_terms( $post_ID, self::TAXONOMY ); /* * Optional - filter out the default category */ if ( 'category' == self::TAXONOMY ) { $default_category_id= get_option('default_category'); foreach( $the_terms as $index => $term ) { if ( $term->term_id == $default_category_id ) { unset( $the_terms[ $index ] ); break; } } } if ( empty( $the_terms ) ) { return; } if ( '' != get_the_post_thumbnail( $post_ID ) ) { return; } /* * Pick the term, e.g. the first value or perhaps a random value */ $chosen_name = $the_terms[0]->name;
There is one other case I’ve thought of but have not addressed. If the new post contains one or more categories that have no images assigned to them, the “Pick the term” line should be changed to avoid choosing a category with no assigned images. That may or may not be a problem in your application.
I hope these revisions get the results you want. Let me know if you find any more problems or have additional questions.
Thanks for the update and your test results; not an inconvenience at all.
I’ve made some changes reflecting what I think you’d like to see. One reason for the ‘no category’ assignment was that the ‘save_post’ hook is called when WordPress “auto saves” the draft as you create the post; I’ve eliminated that. The revised code below changes the logic so an image is only assigned to published posts that have been assigned at least one category other than the default category. You can make any other changes you need to get the results you want.
To make the changes in your code, replace everything from the beginning of the
rfi_save_post_action
function down to the$chosen_name = $the_terms[0]->name;
line that picks the term. The revised code is:function rfi_save_post_action( $post_ID, $post, $update ) { /* * Only assign a random image if (in this order): * 1) The post has been published (avoiding "auto save" revisions) * 2) The post has one or more terms assigned (but not the "default category") * 3) There is no current Featured Image */ if ( 'publish' != $post->post_status ) { return; } $the_terms = get_the_terms( $post_ID, self::TAXONOMY ); /* * Optional - filter out the default category */ if ( 'category' == self::TAXONOMY ) { $default_category_id= get_option('default_category'); foreach( $the_terms as $index => $term ) { if ( $term->term_id == $default_category_id ) { unset( $the_terms[ $index ] ); break; } } } if ( empty( $the_terms ) ) { return; } /* * Remove this if you want to assign a new random image each time the post is updated. */ if ( '' != get_the_post_thumbnail( $post_ID ) ) { return; } /* * Pick the term, e.g. the first value or perhaps a random value */ $chosen_name = $the_terms[0]->name;
There is one other case I’ve thought of but have not addressed. If the new post contains one or more categories that have no images assigned to them, the “Pick the term” line should be changed to avoid choosing a category with no assigned images. That may or may not be a problem in your application.
I hope these revisions get the results you want. Let me know if you find any more problems or have additional questions.
Hello David,
Sorry for bothering you again ?? I got an error when I wanted to add a page to my menu. The error that accoured was:
Warning: Invalid argument supplied for foreach() in \wp-content\plugins\Custom RFI Media Librabry\CustomRFI.php on line 92
(This error message is repeatedly displayed on the screen. )Line 92 is the following code block you supplied above:
if ( 'category' == self::TAXONOMY ) { $default_category_id= get_option('default_category'); foreach( $the_terms as $index => $term ) { if ( $term->term_id == $default_category_id ) { unset( $the_terms[ $index ] ); break; } } }
Despite of the error, the page gets added.
(I got this error message one time before, the exact same error message, but I have forgotten what I did to trigger the error)
Regards, Monique
Monique,
This is an oversight on my part. According to the Codex,
get_the_terms
returns “False if no terms are found in the given taxonomy”. I believe the page you’re adding has not been assigned to any categories. The fix is an easy re-arrangement of the code; move theempty( $the_terms )
test above the default category elimination loop. The revised code should look like this:$the_terms = get_the_terms( $post_ID, self::TAXONOMY ); if ( empty( $the_terms ) ) { return; } /* * Optional - filter out the default category */ if ( 'category' == self::TAXONOMY ) { $default_category_id= get_option('default_category'); foreach( $the_terms as $index => $term ) { if ( $term->term_id == $default_category_id ) { unset( $the_terms[ $index ] ); break; } } }
If that does not resolve the problem, let me know. I haven’t tested this fix but I can’t think of any reason it would fail. Thanks for bringing this issue to my attention!
- The topic ‘Featued Image (Post_thumbnail)’ is closed to new replies.