elementor / elementor

The most advanced frontend drag & drop page builder. Create high-end, pixel perfect websites at record speeds. Any theme, any page, any design.
https://elementor.com/
GNU General Public License v3.0
6.6k stars 1.42k forks source link

📚 Infinite loop when using a `WP_Query` inside `elementor/query/{$query_id}` hook callback #27513

Open vHeemstra opened 5 months ago

vHeemstra commented 5 months ago

Prerequisites

Description

Summary

Detailed cause of the problem

1) Elementor_Post_Query's get_query method hooks into Wordpress' pre_get_posts if a Query ID is set on the widget: _From: ElementorPro\Modules\QueryControl\Classes\Elementor_Post_Query::getquery

    if ( ! empty( $query_id ) ) {
        add_action( 'pre_get_posts', [ $this, 'pre_get_posts_query_filter' ] );
    }

1) After this, it will run the query which will trigger the pre_get_posts hook. 1) The pre_get_posts_query_filter method on the Elementor_Post_Query instance will fire the custom query action:

    do_action( "elementor/query/{$query_id}", $wp_query, $this->widget );

1) If you use any WP_Query (like with get_posts()) in your custom query hook callback, this will fire the pre_get_posts again: _From: WP_Query::getposts

    do_action_ref_array( 'pre_get_posts', array( &$this ) );

1) Since pre_get_posts_query_filter is still hooked and the reference to the widget is still in place, this will call your custom query hook callback again. And the perfect infinite loop has begun!

Possible solution

Steps to reproduce

1) Inside one of your pages, add a Loop Grid widget that fetches posts and set its Query ID to infinite_query. 2) Inside your theme/plugin functions.php, add a custom query hook for the same Query ID:

add_action( 'elementor/query/infinite_query', function ( $query ) {
    // Get IDs we need for filtering in the query
    $ids = get_posts([
        // The arguments here are irrelevant to the problem
        'post_type' => 'posts',
        'fields' => 'ids',
    ]);

    // Irrelevant as well
    $query->set('post__in', $ids);
} );

3) View the page and see either a HTTP 500 error page from your browser or Wordpress' "a critical error has occurred" page.

Expected behavior

I expected Elementor not to start an infinite loop on my website.

Isolating the problem

Elementor System Info

Click to reveal ````txt == Server Environment == Operating System: Linux Software: Apache MySQL version: Ubuntu 22.04 v10.6.16 PHP Version: 8.1.27 PHP Memory Limit: 256M PHP Max Input Vars: 3000 PHP Max Post Size: 8M GD Installed: Yes ZIP Installed: Yes Write Permissions: All right Elementor Library: Connected == WordPress Environment == Version: 6.5.3 Site URL: https://__redacted__ Home URL: https://__redacted__ WP Multisite: No Max Upload Size: 8 MB Memory limit: 256M Max Memory limit: 256M Permalink Structure: /%postname%/ Language: en_EN Timezone: Europe/Amsterdam Debug Mode: Active == Theme == Name: Bug Test Theme Version: 1.0.0 Author: Author Child Theme: Yes Parent Theme Name: Hello Elementor Parent Theme Version: 3.0.1 Parent Theme Author: Elementor Team == User == Role: administrator WP Profile lang: nl-EN User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 == Active Plugins == Elementor Version: 3.21.8 Author: Elementor.com Elementor Pro Version: 3.21.3 Author: Elementor.com == Eigenschappen == Custom Fonts: 0 Custom Icons: 0 == Integraties == woocommerce: Actief == Elementor experimenten == Verbeterd laden van assets: Standaard actief Verbeterd laden van CSS: Standaard actief Pictogrammen inline lettertype: Standaard actief Extra aangepaste breakpoints: Standaard actief admin_menu_rearrangement: Standaard inactief Flexbox container: Standaard actief Upgrade Swiper bibliotheek: Standaard actief Raster container: Standaard actief Geneste elementen prestaties: Standaard inactief Geoptimaliseerde laden van besturing: Standaard inactief Standaard naar nieuwe Thema bouwer: Standaard actief Hello Theme header & footer: Standaard actief Elementor home scherm: Standaard actief Editor top balk: Standaard inactief Bouwen met AI: Standaard actief Landingspagina's: Standaard actief Geneste elementen: Standaard inactief Lazy-load achtergrondafbeeldingen: Standaard actief Weergave voorwaarden: Standaard actief Formulierinzendingen: Standaard actief Menu: Standaard inactief Taxonomiefilter: Standaard actief == Elementor - Compatibility Tag == Elementor Pro: Compatibel == Elementor Pro - Compatibility Tag == ````

Agreement

areiterer commented 4 months ago

Is there any news on this issue? I'm trying to use a custom query that needs a second WP_Query inside, which leads to the above error.

steveindzine commented 3 months ago

I am having the same issue, as I am trying to use get_field within a custom query. I have previously been able to use transients to get around this issue, but the get_field is user specific, so transients won't work here. I need to find another way to pass a user specific array to the query.

steveindzine commented 3 months ago

I am having the same issue, as I am trying to use get_field within a custom query. I have previously been able to use transients to get around this issue, but the get_field is user specific, so transients won't work here. I need to find another way to pass a user specific array to the query.

I ended up using session variables to get around this problem.