Make WordPress Core

Opened 12 years ago

Closed 7 years ago

#21894 closed defect (bug) (duplicate)

<!--more--> tag does nothing in secondary loops when is_single because of $more global

Reported by: jeremyclarke's profile jeremyclarke Owned by: swissspidy's profile swissspidy
Milestone: Priority: normal
Severity: normal Version:
Component: Posts, Post Types Keywords: has-patch needs-refresh
Focuses: template Cc:


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.


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)

fix-more-tag-599068.diff (1.1 KB) - added by jeremyclarke 12 years ago.
fix more tag in get_the_content() in wp-includes/post-template.php
fix_more_setup_postdata_21852.diff (480 bytes) - added by jeremyclarke 12 years ago.
fix more tag via setup_postdata
21894.diff (524 bytes) - added by obenland 10 years ago.

Download all attachments as: .zip

Change History (15)

12 years ago

fix more tag in get_the_content() in wp-includes/post-template.php

#1 @jeremyclarke
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.

12 years ago

fix more tag via setup_postdata

#2 @jeremyclarke
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.

#3 @SergeyBiryukov
12 years ago

  • Component changed from Formatting to Template
  • Version trunk deleted

#4 @knutsp
12 years ago

  • Cc knut@… added

#5 @knutsp
12 years ago

  • Keywords has-patch added

Can we fix this for 3.6, please?

#6 @Veraxus
11 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.

#7 @thpani
11 years ago

  • Cc thpani added

#8 @nacin
10 years ago

  • Component changed from Template to Posts, Post Types
  • Focuses template added

10 years ago

#9 @obenland
10 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.

#10 @chriscct7
9 years ago

  • Keywords needs-refresh added

#11 @swissspidy
7 years ago

  • Owner set to swissspidy
  • Status changed from new to assigned

See also #36934. Could $more become a property of WP_Post?

#12 @swissspidy
7 years ago

  • Milestone Awaiting Review deleted
  • Resolution set to duplicate
  • Status changed from assigned to closed

It looks like this particular scenario was improved by @boonebgorges in [30085] and that it's actually a duplicate of #25349.

I'll keep an eye on that area in #36934 as well.

Note: See TracTickets for help on using tickets.