The problem here is a misunderstanding of what is_single means, reading the docs clarifies this:
https://developer.wordpress.org/reference/functions/is_single/
Is the query for an existing single post?
Description
Works for any post type, except attachments and pages
If the
$postparameter is specified, this function will additionally check if the query is for one of the Posts specified.
So in a post listing, is_single is false, but on a blog post it is true. The same is true for a product, or another custom post type.
So this has more in common with is_page than pagination. A catch all function for this is is_singular
Remember, you can read the docs to verify things, and don’t always assume. E.g. alternative bad assumptions that could be made:
is_singledetermines if the site has a single blog, and returns false if it’s a multisiteis_singlereturns true if the post is the only post in a categoryis_singlechecks if the user has a single item in their shopping cart
So How Do I Find Out How Many Pages a Post Has?
To display the pagination links, we use wp_link_pages, so we can pass the echo parameter and set it to false. This lets us test if it returned markup. If it did, then yes there’s more than one page. If it did not, then no there is only 1 page
$pages = wp_link_pages( ['echo' => false ] );
if ( !empty( $pages ) ) {
// more than 1 page
} else {
// only 1 page
}
A More Specific But Not As Elegant Method
There is a global variable named $multipage that is true if there is more than one page
global $multipage;
if ( $multipage ) {
// there's more than one page
}