2

This link solves the problem but it's only for the main query. What if you are using a custom query? How can you modify the answer below:

add_action('pre_get_posts', 'ad_custom_query');
function ad_custom_query($query) {

    if ($query->is_main_query() && is_home()) { //how can we for specific custom query?

        // set the number of posts per page
        $posts_per_page = 12;
        // get sticky posts array
        $sticky_posts = get_option( 'sticky_posts' );

        // if we have any sticky posts and we are at the first page
        if (is_array($sticky_posts) && !$query->is_paged()) {

            // counnt the number of sticky posts
            $sticky_count = count($sticky_posts);

            // and if the number of sticky posts is less than
            // the number we want to set:
            if ($sticky_count < $posts_per_page) {
                $query->set('posts_per_page', $posts_per_page - $sticky_count);

            // if the number of sticky posts is greater than or equal
            // the number of pages we want to set:
            } else {
                $query->set('posts_per_page', 1);
            }

        // fallback in case we have no sticky posts
        // and we are not on the first page
        } else {
            $query->set('posts_per_page', $posts_per_page);
        }
    }
}

2 Answers 2

1

I think we can try the following: (NOTE: This is untested but should in theory work, but remember, it is untested and can be buggy)

add_action('pre_get_posts', 'ad_custom_query');
function ad_custom_query($query) {
    // No other checks should be necessary
    if ( $query->get( 'custom_query' ) === 1 ) ) {
        // set the number of posts per page
        $posts_per_page = 12;
        // get sticky posts array
        $sticky_posts = get_option( 'sticky_posts' );

        // if we have any sticky posts and we are at the first page
        if (is_array($sticky_posts) && !$query->is_paged()) {

            // counnt the number of sticky posts
            $sticky_count = count($sticky_posts);

            // and if the number of sticky posts is less than
            // the number we want to set:
            if ($sticky_count < $posts_per_page) {
            $query->set('posts_per_page', $posts_per_page - $sticky_count);

            // if the number of sticky posts is greater than or equal
            // the number of pages we want to set:
            } else {
                $query->set('posts_per_page', 1);
            }

        // fallback in case we have no sticky posts
        // and we are not on the first page
        } else {
            $query->set('posts_per_page', $posts_per_page);
        }
    }
}

You can now just do run the following custom query

$args = [
    'custom_query' => 1, // Note, this has to be an integer, '1' will not work
    'paged' = > $paged
// I would just add all the other parameters in the pre_get_posts action
];
$q = new WP_Query( $args );

FEW NOTES:

  • Because we will only target queries where the new custom_query parameter is set to 1, we should not need the checks like !is_admin() or is_main_query()

  • Because we are running a pre_get_posts action on our custom query, I would just set the custom_query and paged parameter in query arguments. Any other parameters I would simply just add in the pre_get_posts action.

  • If you need to run a second query with different parameter and/or values, you can simply set custom_query to 2 and then just check in if the $query->get( 'custom_query' ) has a value of 2, like if ( $query->get( 'custom_query' ) === 2 ) {

  • I have just copied your code and added the new parameter check, I have not worked through your code or changed anything

1

Instead of creating a function I just edited the loop with the custom query. My example is for just one post to show.

I just used if statement if one or more sticky just show the first sticky.

<?php
$sticky_posts = get_option( 'sticky_posts' );
$sticky_count = count($sticky_posts);

if($sticky_count >= 1) {
    $loop = new WP_Query('p=' . $sticky_posts[0]); //show only first sticky
} else {
    $loop = new WP_Query( array( 'post_type' => 'post', 'category__not_in' => 'featured', 'posts_per_page' => 1 ) ); //if none show just the first non-sticky post
}

while ( $loop->have_posts() ) : $loop->the_post();
?>

Your Answer

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