Opened 4 years ago
Last modified 3 years ago
#9256 reopened enhancement
clean up the global variables when moving out of the loop
| Reported by: |
|
Owned by: |
|
|---|---|---|---|
| Priority: | normal | Milestone: | Future Release |
| Component: | Query | Version: | 2.7.1 |
| Severity: | normal | Keywords: | has-patch needs-testing |
| Cc: | gvenk |
Description
On a theme, that I am developing, the sidebar has a new WP_Query to get only one post from a specific category. All works well (index, single, archive, pages) displaying correctly the result of the_content() of the main column (the main query) and the result of the_content() of my custom query in the sidebar.
The problem is that only on pages and articles that have pagination (using the <!--nextpage--> construct), the function "the_content()" of the sidebar displays the same content of the main column on pages 2, 3, 4 (and so on) of those pages/articles, while on page 1 the various contents are displayed properly.
Is it a bug?
As MichaelH reported, using "echo $post->post_content;" fixes the issue temporarily.
Attachments (1)
Change History (13)
comment:2
Viper007Bond — 4 years ago
- Keywords reporter-feedback added; sidebar the_content removed
- Milestone changed from 2.8 to Unassigned
- Keywords needs-patch added
- Milestone changed from Unassigned to Future Release
- Type changed from defect (bug) to enhancement
nah, it's related to the use of globals. even if you actually use the reset query functionality, WP will leave a boat load of globals around that then get used elsewhere.
- Keywords reporter-feedback removed
- Summary changed from Use of the_content() in sidebar to clean up the global variables when moving out of the loop
isn't there a wp_reset_query_vars() or something like that already?
- Component changed from General to Query
- Keywords has-patch needs-testing added; needs-patch removed
in case it's still useful.
Denis-de-Bernardy — 4 years ago
- Resolution set to fixed
- Status changed from new to closed
- Resolution fixed deleted
- Status changed from closed to reopened
I've applied and tested the attached patch to query.php, but using the modified wp_reset_query() function at the end of the single.php loop, for example, still does not prevent the post's content from being output when the_content() is used in the sidebar on the 2nd page of a paginated post.
comment:10
nacin — 3 years ago
- Milestone changed from 2.8 to Future Release
comment:11
mdgl — 3 years ago
I think the problem here is in "setup_postdata()" (query.php) and its handling of global variables.
The function "setup_postdata()" sets the global variable "$page" based on the instance variables of the global query object, i.e. "$page = get_query_var('page')".
Of course if you have done a separate query (e.g. with "get_posts()", "get_children()" or a new "WP_Query" object) and are trying to make use of the template functions by calling "setup_postdata()", this is incorrect as the value of "$page" should be related to your separate query, not the enclosing loop.
The problem is further compounded because "setup_postdata()" only overwrites the first entry in the global "$pages[]" array if your separate query has only a single page. Hence, the other array entries still contain data from the main page and can be inadvertently accessed by function "get_the_content()" using the incorrect value of "$page".
I believe a workaround is to code as follows:
$myposts = &get_posts(...) /* Or new WP_Query or whatever. */
global $post, $page;
$mysavedpost = $post;
foreach ($myposts as $post) {
setup_postdata($post); $page = 1;
the_title(); the_content(); /* And so on. */
}
$post = $mysavedpost; setup_postdata($post);
With the increased use of widgets and complex page templates, such "nested loops" can only become more and more common. Although we're still using global variables in the loop, and "setup_postdata()" still needs to be fixed, a better solution here would be to offer full support for a "save/restore" paradigm for handling nested loops, for example:
$myposts = new WP_Query(...); $myposts->save_loop_state(); /* Copies all required globals into new query object. */ while ($myposts->have_posts()) : $myposts->the_post(); /* Stomps on global variables. */ ... /* Use global variables through template tags. */ endwhile; $myposts->restore_loop_state(); /* Restores all required globals from new query object. */
With a bit of thought, this could perhaps even be made automatic and transparent within the query "have_posts()" and "the_post()" methods, although you would still have to have a method for coping with early exit from the loop.
Presently, we seem to have too much forcing of one loop to run after another, use of "wp_reset_query()" and so on, which is all a bit messy (IMHO).
comment:12
gvenk — 3 years ago
- Cc gvenk added

Are you making sure to use $query_string in your new query? Otherwise the URL parameters saying page 2 has been requested won't be passed.