get_previous_post() while accounting for sticky posts

Ok, this might be overcomplicating things a bit, but at least it should work (untested).

Just call the function like so

get_adjacent_without_sticky( get_the_ID(), true); // get previous post
get_adjacent_without_sticky( get_the_ID(), false); // get next post

This could have been solved easily, if get_previous_post() allowed for an ID to pass and not only run it in the context of the current post. Now you could copy the function code of get_adjacent_post() and adjust it to your needs, but I don’t like messing directly with SQL inside WordPress, so using the common functions it should work like this:

function get_adjacent_without_sticky($id, $previous = true) {

    // get date of current post as reference
    $date = explode('.', get_the_date('d.m.Y', $id));
    $date_array = array(
        'day' => $date[0],
        'month' => $date[1],
        'year' => $date[2],
    );

    // for previous post we need the first post before current one
    if ($previous) {
        $order="DESC";
        $date_query = array(
            'before' => $date_array,
        );
    }
    // for next post we need the first post after current one
    else {
        $order="ASC";
        $date_query = array(
            'after' => $date_array,
        );
    }

    $args = array(
        // order sticky posts as regular ones
        'ignore_sticky_posts' => 1,
        // get only the one post we want
        'posts_per_page' => 1,
        'order' => $order,
        'orderby' => 'date',
        'date_query' => $date_query,
    );

    // now run that query
    $the_query = new WP_Query($args);
    if ($the_query->have_posts()) {
        $the_query->the_post();
        $result = get_post( get_the_ID() );
    } else {
        $result = NULL;
    }
    wp_reset_postdata(); // Restore original Post Data

    return $result;
}

Related topics:

(My answer is bascially these two sources combined into a function.)