Include Sticky Posts in Page Post Count for custom query

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