Add additional first page, last page links to the_posts_pagination()

the_posts_pagination() is an echo wrapper for get_the_posts_pagination(). The getter generates pagination links with paginate_links(), which returns a string with the links separated by a newline character by default.

This string is passed to _navigation_markup() to get the complete pagination markup. We can manipulate the paginate_links() output with paginate_links_output filter, before the navigation markup is generated.

The filter recieves the default links string and pagination arguments as parameters. From $args you can get the total page count as well as the link format.

Here’s an example implementation where the filtering is limited to the specific use case by first adding the filter and then removing it after calling the pagination function. The custom template function would be used insted of the_posts_pagination() in template files.

function my_pagination_link_url(array $args, int $current, string $text) {
    // duplicated / modified from https://developer.wordpress.org/reference/functions/paginate_links/
    $link = str_replace( '%_%', $args['format'], $args['base'] );
    $link = str_replace( '%#%', $current, $link );

    return sprintf(
        '<a class="page-numbers" href="%s">%s</a>',
        $link,
        $text
    );
}

function my_first_pagination_link(array $args) {
  return my_pagination_link_url(
    $args, 1, 'My first'
  );
}

function my_last_pagination_link(array $args) {
  return my_pagination_link_url(
    $args, $args['total'], 'My last'
  );
}

// $args, https://developer.wordpress.org/reference/functions/paginate_links/
function my_add_links_to_pagination( $pagination_html, $args ) {
    return implode('', [
        my_first_pagination_link($args),
        $pagination_html,
        my_last_pagination_link($args),
        // ...my everything?
    ]);
}

function my_the_posts_pagination() {
  add_filter( 'paginate_links_output', 'my_add_links_to_pagination', 10, 2 );

  the_posts_pagination([
    'screen_reader_text' => ' ',
    'mid_size'  => 2,
    'prev_text' => __( 'vorherige', 'bdb' ),
    'next_text' => __( 'nächste', 'bdb' ),
  ]);

  remove_filter( 'paginate_links_output', 'my_add_links_to_pagination', 10 );
}

P.S. Modify the filters and add logic as needed.