Opened 12 years ago
Closed 8 years ago
#21894 closed defect (bug) (duplicate)
<!--more--> tag does nothing in secondary loops when is_single because of $more global
Reported by: | jeremyclarke | Owned by: | swissspidy |
---|---|---|---|
Milestone: | Priority: | normal | |
Severity: | normal | Version: | |
Component: | Posts, Post Types | Keywords: | has-patch needs-refresh |
Focuses: | template | Cc: |
Description
In the sidebar of single posts I have a listing of short posts from a particular category. We recently started using the <!--more-->
system to define teasers because in this case excerpts are overkill. The "more" system works for archive views but does nothing in the sidebar of single posts. The reason is the overly global nature of the global $more
variable. It gets defined in setup_postdata()
like this:
if ( is_single() || is_page() || is_feed() ) $more = 1;
Then in get_the_content()
global $more is checked to determine whether to apply the effect of the <!--more-->
tag or not:
if ( $more ) { // show full content with span ID } else { // show intro text and more link }
This means that any time is_single()
is true all posts shown during the pageload ignore <!--more-->
, even those who's is_single
view we are not on.
This seems like an understandable result of the unpopularity of the more tag (and rareness of showing "full" posts in secondary loops), but also something that should be fixed. Only the post who's single view we are looking at should have the more tag disabled based on the is_single()
check.
SOLUTION
As far as I can tell what's needed is to modify get_the_content()
and in addition to using global $more
, also check if the post being shown is the same as get_queried_object()
. My first instinct was to just add the check in the if
statement above:
if ( $more AND ( $post-ID == get_the_queried_object_id() ) ) { // show full content with span ID } else { // show intro text and more link }
Unfortunately that will screw with the is_feed()
-related checks for global $more
. Overall my investigation of $more
is making me think it should be removed entirely, as it's only used a few times and in all cases its meaning is vague.
Either way I think the simplest way to handle the issue in get_the_content()
without completely stripping out $more
is to use $more
as the base for a $show_full_content
variable, then set that to false if $post->ID
doesn't match get_queried_object_id()
:
$show_full_content = $more; if ( is_single() OR is_page() ) { if ($post->ID != get_queried_object_id()) $show_full_content = false; }
The new variable gives a better sense of what it will do inside this function, and lets us change the value without stomping the global $more
. The attached patch fixes get_the_content()
as described above.
If core devs are willing to I think the best solution would be to remove all uses of $more
and simply replace them with the appropriate logic for the given situation like I've done above for get_the_content()
.
Attachments (3)
Change History (15)
#1
@
12 years ago
While preparing a plugin-based temporary solution to this I realized that I attacked it from the wrong angle. I somehow didn't think of the fact that setup_postdata()
gets run for each post, and $more is initialized for each spin of the loop.
It seems clear that the actual right place to put the new logic is in setup_postdata()
:
if ( ( is_single() || is_page() ) && ( $id == get_queried_object_id() ) ) $more = 1; if ( is_feed()) $more = 1;
Sorry for adding noise. I think changing setup_postdata() si an even more obvious win than the change in get_the_content(), though both will solve my problem.
#2
@
12 years ago
That last patch is slightly different than described. I realized I can just pass $id to is_single() and is_page() to ensure it checks that we're dealing with the core single-post for the page. It also sets $more to false before the check, otherwise it gets set to true on the first loop (the main single post) and never gets set to false for other posts that don't match the if statement.
#6
@
12 years ago
I agree, this should be fixed, but I'm not sure the provided patch is the right answer.
Currently, the workaround solution for developers is to explicitly set $more = false before the new custom loop, which isn't a huge deal... (although if you want to preserve the original value, you would have to briefly store it in another variable and restore it after the loop).
I think a more developer-centric solution would be to provide the ability to set handing of the more tag as a query parameter... although that would involve modifying more WordPress components to provide support.
#9
@
11 years ago
Unfortunately, setup_postdata()
is not context aware when it checks for single, page, and feed. Passing the post ID gives some context, but it's still not possible to check if it's called outside of the main query.
Refreshed patch sets $more
to 0 or 1, as mentioned earlier. This should cover most use cases. It doesn't work if the post in the custom query happens to be the current post of the main query.
fix more tag in get_the_content() in wp-includes/post-template.php