0

I have a custom made widget for elementor, but my problem is that my loop to get posts doesn't work properly. Currently, it returns the title of the page where the widget was inserted, doesn't show the actual posts. Here's the relevant part of my code:

    $args  = array(
        'posts_per_page'  => 12,
        'category_name'   => 'featured',
        'orderby'         => 'post_date',
        'order'           => 'ASC',
        'post_type'       => 'post',
        'suppress_filters' => true ); 
    $posts = get_posts($args);
        foreach ($posts as $post) :




            echo '<div class="posts-carousel swiper-container">';
            echo '<div class="swiper-wrapper">';

            echo    '<div class="swiper-slide carousel-post" style="background:url(';
            echo the_post_thumbnail('large');
            echo ');"><div class="text">';
            echo the_title();
            echo '</div><div class="overlay"></div></div>';

            echo '</div>';

            echo    '<div class="swiper-pagination"></div>';

            echo    '<div class="swiper-button-prev"></div>';
            echo    '<div class="swiper-button-next"></div>';
            echo '</div>';

        endforeach;

Anyone knows how could I make it work?

  • Note that setting suppress_filters to true can have major performance penalties. Also I notice you used get_posts instead of a standard post loop? And you never set the current post at the start of each loop? So the_title and the_post_thumbnail always refer to the main page, not the current post you're looping over? – Tom J Nowell Oct 24 at 22:07
  • @TomJNowell Thanks, you are right, I will remove the suppress_filters. I would like the the_title and the_post_thumbnail to refer to the current post in the loop and never to the main page. What would be the best way to set the current post? Thank you – lastnoob Oct 24 at 22:20
1

I would recommend switching to a standard post loop:

    $args  = [
        'posts_per_page'  => 12,
        'category_name'   => 'featured',
        'orderby'         => 'post_date',
        'order'           => 'ASC',
    ]; 
    $query = new \WP_Query($args);
    if ( $query->have_posts() ) {
        while ( $query->have_posts() ) {
            $query->the_post();
            .....
        }
        \wp_reset_postdata();
    }

Note that I:

  • switched to modern PHP array syntax of [] rather than array()
  • removed the suppress filters parameter
  • switched to a standard \WP_Query loop
  • checked if any posts were actually found, providing a way to add an else statement with a "no posts found" message
  • switched to standard PHP syntax with {} brackets rather than the alternate syntax
  • fixed the indenting
  • called the_post() to set the current post, equivalent to setup_postdata( $post ); but cleaner
  • called wp_reset_postdata() to clean up after the loop so that the next piece of code gets the correct post, not the last post the loop iterated over
  • removed the post_type parameter as the default post type is already post
  • You mentioned in a comment there was a namespace related error, so I added \ to ensure it pulled WP functions from the global namespace

I do have 2 unrelated notes though:

Return Values and the_ functions

I spotted these:

            echo the_post_thumbnail('large');

and

            echo the_title();

These functions don't return a value to echo, that's not how they work. They are equivalent to:

echo '';
the_post_thumbnail('large');
echo '';
the_title();

So don't use echo, the same goes for any other WP function beginning with the_ such as the_content, etc. If you really need the value returned so you can put it in a variable, use the equivalent get_ style functions.

Carousel Markup

If I understand right, if 5 posts are found, there will be 5 carousels, each with a single post in them. I would move the carousel container markup to before and after the loop, so that inside it you're only outputting the current slide/item.

In general though, carousels have apalling UX, poor accessibility, high complexity, and a high overhead on performance and CSS/JS weight. You would be better off with a hero pattern, or a featured grid of some sort, carousels have extremely poor discoverability, so any carousel will be just as effective as showing the first item and not showing the rest. Setting 'posts_per_page' => 1 will be just as effective.

  • Thanks for all the information. It's very useful. I made some rookie mistakes there, I appreciate you correcting me. Unfortunately, using the standard loop with WP_Query in an Elementor widget gives me an error: Class 'Elementor\WP_Query' not found. Any idea why that is? – lastnoob Oct 28 at 11:30
  • Just prefix WP_Query with a backslash, e.g. \WP_Query, it's a PHP namespace thing, I've edited the code accordingly, and fixed a slip up I made – Tom J Nowell Oct 28 at 13:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.