Append URL query to next post link in custom query

Deep down that function uses get_pagenum_link(). This is filterable with the get_pagenum_link filter. So you could add and remove that filter that uses a global variable that gets set in your function before the link is retrieved:

function wpse_287817_add_query_args( $url ) {
    global $wpse_287817_query_args;

    return add_query_arg( $wpse_287817_query_args, $url );
}
add_filter( 'get_pagenum_link', 'wpse_287817_add_query_args', 10 );

function wpse_287817_get_next_posts_link( $label = null, $max_page = 0, $query_args = array() ) {
    global $wpse_287817_query_args;

    $wpse_287817_query_args = $query_args;

    $link = get_next_posts_link( $label, $max_page );

    return $link;
}

Then you’d use it like this:

$query_args = array(
    'q1' => 'cats',
    'q2' => 'lasers',
);

echo wpse_287817_get_next_posts_link( 'Next', $max_page, $query_args );

It’s pretty messy, because of the need to use a global variable to pass the values to be added to the URL. So if you don’t need to actually pass the query args into the function, and can get them from within the filter callback, do that.

For example, if you’re are just trying to preserve $_GET[] variables that are on the URL, you don’t need a custom function or global variable at all, and can just set them in the callback:

function wpse_287817_add_query_args( $url ) {
    $query_args = array();

    if ( isset( $_GET['my_var'] ) ) {
        $query_args[] = $_GET['my_var'];
    }

    if ( isset( $_GET['my_other_var'] ) ) {
        $query_args[] = $_GET['my_other_var'];
    }

    return add_query_arg( $query_args, $url );
}
add_filter( 'get_pagenum_link', 'wpse_287817_add_query_args', 10 );