get posts returns results but wp_query does not

The main problem is a misunderstanding of PHP objects and the 2 methods you’re using:

$a = get_posts( ... );
$b = new WP_Query( ... );
  • $a is an array of WP_Post objects
    • e.g. foreach ( $a as $p ) { ... }
  • $b is an object of type WP_Query
    • e.g. while ( $b->have_posts() ) { $b->the_post(); .... }

Most importantly, get_posts is a wrapper around WP_Query! So much so that the array of posts is $b->posts, but beware that by accessing it you skip any lazy loading optimisations in place. The same is somewhat true of using get_posts, and you would still need to call setup_postdata inside the loop for each post to set the current post, followed by wp_reset_postdata at the end.

A Note on wp_reset_query

This function is not for cleaning up after get_posts or WP_Query. Though it will appear to work, it does more than that. This is because it’s intended to reset the query itself after using query_posts(...) to overwrite the main query. Since query_posts is a major mistake in 99% of cases it’s safe to say you should never use it, and neither should you use wp_reset_query.

Instead, this is how you perform a standard post loop using a query:

$args = [ ... ];
$query = new WP_Query( $args );
if ( $query->have_posts() ) {
    while( $query->have_posts() ) {
        $query->the_post();
        // output inner loop, get_the_ID and standard functions such as `the_title()` will work in here
    }
    wp_reset_postdata();
}

Notice I did not do foreach ( $query->posts as $post ) { as this would not set the current post globals, and it would not perform lifecycle filters and hooks. I also only call wp_reset_postdata at the very end after the loop, but, I do it inside the if condition so it does not happen if there are no posts. I also checked if the query had posts, this gives an opportunity to print out things before/after the loop such as <ul> and </ul> etc

Further reading:

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)