简体   繁体   中英

How can I sort posts by featured image(no image posts at the bottom) in wordpress using PHP?

I am working with the Wordpress Query Object using the WP Types/Views Toolset. http://wp-types.com

We built out the parametric search which allows the user to search through posts using various taxonomies. It works fine, it display search results as needed. BUT..

Most of the posts don't have featured images, we want to display posts with featured images at the top, and the featured imageless posts would go below.

I have a good head start on this as far as logic goes, just need a bit of help.

The code below allows me manipulate the query before rendering it to the user.

add_filter( 'wpv_filter_query_post_process', 'prefix_rearrange_by_thumbnail', 10, 3 );

    function prefix_rearrange_by_thumbnail( $query, $view_settings, $view_id ) {
        // sort posts by thumbnail
    return $query;
}

How can I sort through the query->posts and rearrange them so the ones that do have featured images show up before those without.

All of the WP_Post objects are found in an array under $query->posts . You can sort the array using usort() based on whatever criteria you want. Keep in mind that this will only sort each page of results as that is what is returned.

add_filter( 'wpv_filter_query_post_process', 'prefix_rearrange_by_thumbnail' );
function prefix_rearrange_by_thumbnail( $query ) {
    $posts = $query->posts;
    usort( $posts, 'sort_by_thumbnail' );
    return $query;
}

// function used to sort the posts array
function sort_by_thumbnail( $a, $b ){
    // the the featured image id so we can sort by it
    $a_thumb = get_post_meta( $a->ID, '_thumbnail_id', true );
    $b_thumb = get_post_meta( $b->ID, '_thumbnail_id', true );

    if ( empty( $a_thumb ) && ! empty( $b_thumb ) ) return 1;
    if ( ! empty( $a_thumb ) && empty( $b_thumb ) ) return -1;
    return 0;
}

To sort all the pages of the results you need to modify the arguments that are passed to WP_Query using the wpv_filter_query filter. There is a meta_key called "_thumbnail_id" set for each post/page that has a featured image, but the issue is that this meta_key is not set at all for posts/pages without a featured image, so if you use it the results will be sorted by the ID of the featured images, but if it is missing they will be omitted. One option is to set another flag based on that meta_key to use in your sort. A one time cleaned would be needed then you could use a hook on save_post

One time SQL (adjust for your db prefix):

INSERT INTO wp_postmeta( post_id, meta_key, meta_value )
SELECT p.ID, '_has_featured_image', IF ( meta_value IS NULL, 0, 1 ) AS _has_featured_image
FROM wp_posts p
LEFT JOIN wp_postmeta m ON p.ID  = m.post_id AND meta_key = '_thumbnail_id'
WHERE p.post_status = 'publish'
AND p.post_type IN ('post','page')

Hook on save_post to keep "_has_featured_image" clean going forward:

add_action( 'save_post', 'set_has_featured_image' );
function set_has_featured_image( $post_id ){
    $post = get_post( $post_id );
    switch ( $post->post_type ){
        case 'post': case 'page':
            $thumbnail_id = get_post_meta( $post_id, '_thumbnail_id', true );
            update_post_meta( $post_id, '_has_featured_image', ! empty( $thumbnail_id ) );
        break;
    }
}

Now you can filter on the "_has_featured_image" meta_key :

add_filter( 'wpv_filter_query', 'prefix_rearrange_by_thumbnail' );
function prefix_rearrange_by_thumbnail( $args ){ 
    $args['orderby'] = 'meta_value';
    $args['meta_key'] = '_has_featured_image';
    return $args;
}

I managed to do it in an easier way...

add_filter( 'wpv_filter_query_post_process', 'prefix_rearrange_by_thumbnail', 10, 3 );
function prefix_rearrange_by_thumbnail( $query, $view_settings, $view_id ) {
    if ( !empty( $query->posts ) ) {

        $sorted_posts_top = array();
        $sorted_posts_bottom = array();
        $all_posts = $query->posts;

        foreach ($all_posts as $post) {

            if ( has_post_thumbnail($post->ID) ) {
                $sorted_posts_top[] = $post;
                }
            else {
                $sorted_posts_bottom[] = $post;
            }

          $query->posts = array_merge((array)$sorted_posts_top, (array)$sorted_posts_bottom);

        }

    }
    return $query;
}

However, your answer is still VERY helpful. Thank you SO MUCH for sharing!!!!!!!!!!!!!!!!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM