loop - How to filter get previous post function by meta value DESC and post date DESC?

admin2025-01-08  3

My loop displays featured posts and then posts in reverse chronological order.

However when I use <?php echo get_previous_post(); ?> it grabs posts in reverse chronological order.

How do I add a filter to the previous post function similiar to this but instead filter by an array like this: 'orderby' => array( 'meta_value' => 'DESC', 'date' => 'DESC') ?


Code:


UPDATE: Cleaned up index.php loop after help from @sMyles and @JackJohansson

Index.php loop:

$args = array(
    'posts_per_page'    => - 1,
    'meta_key'          => 'meta-checkbox',
    'orderby'           => array( 'meta_value' => 'DESC', 'date'  =>  'DESC')

);

$posts = new WP_Query( $args );

if($posts->have_posts() ){

    while( $posts->have_posts() ){

        $posts->the_post();

        // Set to content template by default
        $template = 'content';

        // Change template to featured when `is_featured` meta has a value
        if(get_post_meta(get_the_ID(), 'meta-checkbox', 'yes')){
            $template = 'featured';
        }

        // Load template part
        get_template_part( $template, get_post_format() );

    }
}


UPDATE: As suggested, I added where I use the previous post function

Previous Post Function

<div id="next-post">
    <?php $prev_post = get_previous_post();
    if(!empty($prev_post)) {
        echo '<a class="next-story" href="' . get_permalink($prev_post->ID) . '">Next Story</a>'; 
        echo '<a class="next-story-title" href="' . get_permalink($prev_post->ID) . '" title="' . $prev_post->post_title . '">' . $prev_post->post_title . '</a>'; 
    } ?>
</div>


Function For Featured Posts:

function sm_custom_meta() {
    add_meta_box( 'sm_meta', __( 'Featured Posts', 'sm-textdomain' ), 'sm_meta_callback', 'post' );
}
function sm_meta_callback( $post ) {
    $featured = get_post_meta( $post->ID );
?>

<p>
<div class="sm-row-content">
    <label for="meta-checkbox">
        <input type="checkbox" name="meta-checkbox" id="meta-checkbox" value="yes" <?php if ( isset ( $featured['meta-checkbox'] ) ) checked( $featured['meta-checkbox'][0], 'yes' ); ?> />
        <?php _e( 'Featured this post', 'sm-textdomain' )?>
    </label>

</div>
</p>

<?php
}
add_action( 'add_meta_boxes', 'sm_custom_meta' );

function sm_meta_save( $post_id ) {

    // Checks save status
    $is_autosave = wp_is_post_autosave( $post_id );
    $is_revision = wp_is_post_revision( $post_id );
    $is_valid_nonce = ( isset( $_POST[ 'sm_nonce' ] ) && wp_verify_nonce( $_POST[ 'sm_nonce' ], basename( __FILE__ ) ) ) ? 'true' : 'false';

    // Exits script depending on save status
    if ( $is_autosave || $is_revision || !$is_valid_nonce ) {
        return;
    }

    // Checks for input and saves
    if( isset( $_POST[ 'meta-checkbox' ] ) ) {
        update_post_meta( $post_id, 'meta-checkbox', 'yes' );

    } else {
        update_post_meta( $post_id, 'meta-checkbox', '' );
    }

}
add_action( 'save_post', 'sm_meta_save' );

My loop displays featured posts and then posts in reverse chronological order.

However when I use <?php echo get_previous_post(); ?> it grabs posts in reverse chronological order.

How do I add a filter to the previous post function similiar to this but instead filter by an array like this: 'orderby' => array( 'meta_value' => 'DESC', 'date' => 'DESC') ?


Code:


UPDATE: Cleaned up index.php loop after help from @sMyles and @JackJohansson

Index.php loop:

$args = array(
    'posts_per_page'    => - 1,
    'meta_key'          => 'meta-checkbox',
    'orderby'           => array( 'meta_value' => 'DESC', 'date'  =>  'DESC')

);

$posts = new WP_Query( $args );

if($posts->have_posts() ){

    while( $posts->have_posts() ){

        $posts->the_post();

        // Set to content template by default
        $template = 'content';

        // Change template to featured when `is_featured` meta has a value
        if(get_post_meta(get_the_ID(), 'meta-checkbox', 'yes')){
            $template = 'featured';
        }

        // Load template part
        get_template_part( $template, get_post_format() );

    }
}


UPDATE: As suggested, I added where I use the previous post function

Previous Post Function

<div id="next-post">
    <?php $prev_post = get_previous_post();
    if(!empty($prev_post)) {
        echo '<a class="next-story" href="' . get_permalink($prev_post->ID) . '">Next Story</a>'; 
        echo '<a class="next-story-title" href="' . get_permalink($prev_post->ID) . '" title="' . $prev_post->post_title . '">' . $prev_post->post_title . '</a>'; 
    } ?>
</div>


Function For Featured Posts:

function sm_custom_meta() {
    add_meta_box( 'sm_meta', __( 'Featured Posts', 'sm-textdomain' ), 'sm_meta_callback', 'post' );
}
function sm_meta_callback( $post ) {
    $featured = get_post_meta( $post->ID );
?>

<p>
<div class="sm-row-content">
    <label for="meta-checkbox">
        <input type="checkbox" name="meta-checkbox" id="meta-checkbox" value="yes" <?php if ( isset ( $featured['meta-checkbox'] ) ) checked( $featured['meta-checkbox'][0], 'yes' ); ?> />
        <?php _e( 'Featured this post', 'sm-textdomain' )?>
    </label>

</div>
</p>

<?php
}
add_action( 'add_meta_boxes', 'sm_custom_meta' );

function sm_meta_save( $post_id ) {

    // Checks save status
    $is_autosave = wp_is_post_autosave( $post_id );
    $is_revision = wp_is_post_revision( $post_id );
    $is_valid_nonce = ( isset( $_POST[ 'sm_nonce' ] ) && wp_verify_nonce( $_POST[ 'sm_nonce' ], basename( __FILE__ ) ) ) ? 'true' : 'false';

    // Exits script depending on save status
    if ( $is_autosave || $is_revision || !$is_valid_nonce ) {
        return;
    }

    // Checks for input and saves
    if( isset( $_POST[ 'meta-checkbox' ] ) ) {
        update_post_meta( $post_id, 'meta-checkbox', 'yes' );

    } else {
        update_post_meta( $post_id, 'meta-checkbox', '' );
    }

}
add_action( 'save_post', 'sm_meta_save' );
Share Improve this question edited Jul 1, 2017 at 0:34 Nick M. asked Jun 28, 2017 at 18:30 Nick M.Nick M. 74 bronze badges 8
  • Is there any reason in particular that you aren't using the sticky post feature? With sticky posts you could use the original unmodified query and could add an is_sticky() check in your loop to get the appropriate template part. – Dave Romsey Commented Jun 28, 2017 at 19:14
  • But that's what exactly sticky posts do. Sticky posts are shown first, then non-sticky posts will be shown. – Johansson Commented Jun 30, 2017 at 17:50
  • sticky is a featured just like is_home or is_single. Each post object contains a value that determines whether a post is featured or not. All you need is $post->is_sticky() to check if it's sticky or not. You don't even have to change the loop, sticky posts are always shown first in the loop, unless you set ignore_sticky_posts to 1 in your query's arguments. – Johansson Commented Jun 30, 2017 at 17:53
  • @DaveRomsey I believe sticky posts don't change how the get_previous_post function works. From wp-includes/link-template.php: core.trac.wordpress.org/browser/tags/4.8/src/wp-includes/… – Nick M. Commented Jun 30, 2017 at 20:08
  • @NickM. Yep, you're right. – Dave Romsey Commented Jun 30, 2017 at 20:31
 |  Show 3 more comments

2 Answers 2

Reset to default 0

You should just do a new full query for all posts (not just featured ones), and set the orderby to meta_value and just check when doing the loop, if that post meta value is yes, and output the featured template, otherwise output standard one.

https://codex.wordpress.org/Class_Reference/WP_Query#Order_.26_Orderby_Parameters

UPDATE: Maybe something like this:

$args = array(
    'posts_per_page'    => - 1,
    'meta_key'          => 'meta-checkbox',
    'orderby'           => array( 'meta_value' => 'DESC', 'date'  =>  'DESC')

);

$posts = new WP_Query( $args );

if($posts->have_posts() ){

    while( $posts->have_posts() ){

        $posts->the_post();

        // Set to content template by default
        $template = 'content';

        // Change template to featured when `is_featured` meta has a value
        if(get_post_meta(get_the_ID(), 'meta-checkbox', true )){
            $template = 'featured';
        }

        // Load template part
        get_template_part( $template, get_post_format() );

    }
}

You will notice I changed the meta key to is_featured .. it's good practice to use underscores instead of hyphens.

To get the value for meta on the post, just use the $post object which has a __get PHP magic method which will return post meta if it exists.

http://php.net/manual/en/language.oop5.overloading.php#object.get

Add this to your child theme's functions.php file to modify the main posts loop query:

add_action( 'pre_get_posts', 'smyles_main_query_custom_orderby' );
/**
 *  Modify main post query sort by meta key and date
 *
 * @param \WP_Query $query
 */
function smyles_main_query_custom_orderby( $query ) {

    // Verify query is main blog archive
    if ( $query->is_home() && $query->is_main_query() ) {
        $query->set( 'meta_key', 'meta-checkbox' );
        $query->set( 'orderby', array( 'meta_value' => 'DESC', 'date' => 'DESC' ) );
    }

}

https://codex.wordpress.org/Plugin_API/Action_Reference/pre_get_posts https://make.wordpress.org/core/2014/08/29/a-more-powerful-order-by-in-wordpress-4-0/

Your index.php file loop can then just look like this:

if ( have_posts() ) {

    while( have_posts() ) {

        the_post();

        $template = get_post_meta( get_the_ID(), 'meta-checkbox', true ) ? 'featured' : 'content';
        // This could have just been the code below had you used underscores like I previously mentioned
        // $template = $post->meta_checkbox ? 'featured' : 'content';

        // Load template part
        get_template_part( $template, get_post_format() );

    }
}
转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1736268975a1316.html

最新回复(0)