Problem/Motivation

The teaser version of a node always shows a 'Read more' link to the main node page.

In Drupal 6, the "Read more" link shown at the end of a teaser could be configured to show only if the teaser was shorter than the full node.

This made sense when all (or nearly all) of our content resided within the node body, but the field system in Drupal 7 makes the situation rather more complicated.

A D7 node may have zero, one, or several fields of type "text with summary" whose contents may be shortened for the "teaser" display. Other fields may be configured to display in "full" mode but be hidden in "teaser" mode. Other page elements (block, panels, etc) may also display different related content depending on whether the user is viewing a single node/entity or a list of teasers.

Therefore, when the D6 node_teaser() function was renamed to text_summary() for D7, the option to remove the "Read more" was deliberately and intentionally removed. Since there is no easy way to determine whether or not there is "more" to read, the "Read more" link is always shown.

To make matters worse, there are a number of tests that check for the existence of a teaser by looking for its "Read more" link.

For those who are upgrading their D6 sites to D7, this deliberate design decision is widely viewed as a regression and a bug.

Proposed resolution

The proposed approach is to interrogate each field on the node to ask 'are you different in the full node view mode?'.

Most fields will simply say 'no'; a field that is not shown on the teaser automatically says 'yes', and the node body text field carries out the same comparison test as on D6.

The answers from all fields are put together: any reply of 'yes' means the 'read more' link should be generated as before, and if all reply 'no' then the link will not be shown.

There are two ways to "not show" the link, both implemented in #199:

  1. Make the link invisible by setting its class to 'element-hidden'.
  2. Simply do not print the link.

The project Read More Control attempts to resolve this issue by parsing the display modes between the teaser and full view modes and it unsets the link is it decides that the Read more link is not required. Configurable globally or per content type.

Remaining tasks

This issue needs a an in-depth review and sign-off from entity/field system maintainers.

User interface changes

The "Read more" link would only appear when there is actually "more" to read.

API changes

An additional '#read_more' property would be added to renderable node arrays.

Original report by AES2

Trim length is easy to find in D6, but in D7 I had to dig before I found it on Structure, Content Types, Basic page, Edit, Display Settings, and then I set it to Unlimited.

The front page is a single basic page containing nothing but "Lorem ipsum ..." (ellipsis after only the first two words) promoted to the front page.

When displaying the front page from the root of the domain (nothing after dot com/) it always shows the full text followed by a Read more link pointing to .../node/1.

If I click the Read more link or the Primary links entry, both of which point to .../node/1; or if I type .../node/1 in browser's URL field it shows the full text without a Read more link.

D6 does not show a Read more link if the entire text fits on the front page. D7 Alpha 4 and Alpha 5 always show a Read more link on the front page, even if not needed, both in Garland and my own Zen theme.

CommentFileSizeAuthor
#264 read-more-settings.png13.15 KBAlan D.
#256 823380-256.patch1.57 KBswentel
#254 823380-253.patch2.45 KBswentel
#253 Screen Shot 2012-11-09 at 19.14.15.png43.08 KBswentel
#244 Screen Shot 2012-05-31 at 8.48.49 AM.PNG83.94 KByurtboy
#243 drupal-823380-242.patch12.19 KBtim.plunkett
#240 drupal-823380-239.patch12.26 KByurtboy
#238 drupal-823380-238.patch11.67 KBtim.plunkett
#237 drupal-823380-237-tests.patch6.91 KBtim.plunkett
#237 drupal-823380-237-combined.patch11.42 KBtim.plunkett
#235 drupal-823380-235.patch11.35 KBtim.plunkett
#228 823380.228.drupal.node-read-more.concept.patch11.11 KBjoachim
#225 823380.225.drupal.node-read-more.patch11.55 KBjoachim
#224 read-more-823380-223-tests.patch6.72 KBTor Arne Thune
#224 read-more-823380-223.patch11.06 KBTor Arne Thune
#224 interdiff-211-223.txt922 bytesTor Arne Thune
#211 read-more-823380-209-tests.patch6.48 KBxjm
#211 read-more-823380-209.patch10.82 KBxjm
#199 better_read_more-823380+element_hidden-199.patch10.45 KBpillarsdotnet
#199 better_read_more-823380+1300568-199.patch13.79 KBpillarsdotnet
#197 better_read_more-823380+1300568-197.patch13.78 KBpillarsdotnet
#195 better_read_more-823380+1300568-195.patch13.42 KBpillarsdotnet
#193 better_read_more-823380+1300568-193.patch13.43 KBpillarsdotnet
#192 better_read_more-823380+element_hidden-192.patch10.44 KBpillarsdotnet
#191 better_read_more-823380+1300568-191.patch12.59 KBpillarsdotnet
#190 better_read_more-823380+1300568-190.patch13.17 KBpillarsdotnet
#189 better_read_more-823380-189.patch10.44 KBpillarsdotnet
#174 better_read_more-823380-174.patch10.41 KBpillarsdotnet
#171 better_read_more-823380-170.patch12.16 KBpillarsdotnet
#171 interdiff-160-170.txt4.61 KBpillarsdotnet
#172 better_read_more-823380-171.patch12.13 KBpillarsdotnet
#168 better_read_more-823380-167.patch12.46 KBpillarsdotnet
#167 better_read_more-823380-167.patch12.46 KBpillarsdotnet
#165 better_read_more-823380-165.patch12.16 KBpillarsdotnet
#162 better_read_more-823380-162.patch13.89 KBpillarsdotnet
#160 better_read_more-823380-160.patch11.91 KBpillarsdotnet
#131 better_read_more-221257+823380-131.patch33.13 KBpillarsdotnet
#131 better_read_more-221257+823380-131-d7.patch33.13 KBpillarsdotnet
#131 better_read_more-823380-131-d7.patch14.08 KBpillarsdotnet
#131 better_read_more-823380-131.patch14.08 KBpillarsdotnet
#116 better_read_more-823380-116.patch14.08 KBpillarsdotnet
#116 better_read_more-823380-87_to_114-interdiff.txt5.1 KBpillarsdotnet
#114 better_read_more-823380-114.patch14.71 KBpillarsdotnet
#111 better_read_more-823380-111.patch34.48 KBpillarsdotnet
#109 better_read_more-823380-109.patch32.94 KBpillarsdotnet
#108 better_read_more-823380-108.patch30.23 KBpillarsdotnet
#105 Better-read_more-823380-105.patch24.81 KBpillarsdotnet
#103 Better-read_more-823380-103.patch28.61 KBpillarsdotnet
#102 Better-read_more-823380-102.patch28.61 KBpillarsdotnet
#89 field-better_read_more-221257-823380-89.patch24.33 KBpillarsdotnet
#87 better_read_more_823380-87.patch9.01 KBJamie Holly
#78 fix-readmore-link-823380-78.patch22.74 KBJamie Holly
#69 fix-read-more-823380-69.patch7.7 KBJamie Holly
#62 823380.drupal.field-teaser-read-more.patch11.44 KBjoachim
#21 better_read_more_21.patch11.29 KBscito
#21 better_read_more_21_only_tests.patch7.5 KBscito
#19 better_read_more.patch3.93 KBvito_swat
#17 better_read_more.patch4.02 KBvito_swat
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

AES2’s picture

Now I know a little more about how things work. I created an article and promoted it to D7's front page, but I should have created a basic page and made it the default front page. Apparently D7 alpha 6's front page has a Read More link whether there is any more to read or not. I'd like to see at least an option to eliminate the Read More link if there is no more to read, but that's not a serious problem for me.

I was hoping to have a page type like the front page where I could promote articles to other pages and have them show up ordered by weight, but after finding nothing I came to the conclusion that promoting articles to the front page is really only for the front page. I'd still like the simpler option of creating arbitrary pages like the front page, but I discovered views, which work just fine. Thanks to the people who contributed substantial effort to a module that large and that useful.

upandrunning’s picture

Version: 7.0-alpha5 » 7.0-beta2
Priority: Normal » Major

I have no settings to trim the length of a post. I was unable to find them. Thought I was fortunate to find this, but no such setting exists for my site for pages or stories.

I was looking for the setting because I have the same problem reported here: "No trim shows Read More on front page"

Why a "Read More" when it is all displayed?

Haza’s picture

Component: page.module » node.module
Priority: Major » Normal
Status: Active » Closed (won't fix)

According to the code we have in node.module, we don't have any way to know when the teaser is different than the full view, so we can't fix that.

  // Always display a read more link on teasers because we have no way
  // to know when a teaser view is different than a full view.
  $links = array();
  if ($view_mode == 'teaser') {
    $links['node-readmore'] = array(
      'title' => t('Read more'),
      'href' => 'node/' . $node->nid,
      'attributes' => array('rel' => 'tag', 'title' => strip_tags($node->title))
    );
  }
vito_swat’s picture

Title: No trim shows Read More on front page » Read More link is always visible on teaser
Version: 7.0-beta2 » 7.0-rc1
Priority: Normal » Major
Status: Closed (won't fix) » Active

I don't know who agreed to change the behavior of the read more link but for me it is serious degradation as Drupal 6 and before the read more link is behaving more or less like user would expect. Now when we have fields in core it is more difficult to check but still not impossible.

I propose something like that:

1. check if every field in full view is shown in teaser. If no, show read more link
2. check if every shown text field has the same text in teaser and in full view. If no, show read more link

This will provide more intuitive and expected results. The read more link will be shown only if there is really something more to show (more fields, or more text in a field) ie. no read more link if the only difference between teaser and full view of article is the image style used and BTW for node types like old image, users tend to click on images anyway (there's no problem to have image linked to content).

According to point 2 there should be the way to allow other (contrib) fields to be checked for consistency or even make user decide about checking but I think that this part can wait for D8.

mattyoung’s picture

~

mokko’s picture

Can anybody verify if this is behavior exists also in current dev? Then could change the version of this thread and it would receive more attention.

joachim’s picture

Version: 7.0-rc1 » 7.x-dev

Confirming on the latest dev. I agreed this is a regression in behaviour from D6. 'read more' should not show if there is no more to read!

joachim’s picture

Used to work like this on D6:

  // First we'll overwrite the existing node teaser and body with
  // the filtered copies! Then, we'll stick those into the content
  // array and set the read more flag if appropriate.
  $node->readmore = $node->teaser != $node->body;

Then hook_link() would check for that flag.

Morn’s picture

~

vito_swat’s picture

joachim:
We cannot rely on the code from D6 as fields in core feature eliminated the mandatory body field. Case is more complicated and I guess that's why they put the read more link always on but this is not it supposed to work in my opinion.
I will try to provide some preliminary patch in 2-3 days.

joachim’s picture

I guess then we can expand the logic to this:

- is there a 'body' field on this node?
  - yes:
    - does its summary differ from its full text?
      - yes: show 'read more'
      - no: show nothing
  - no: show 'read more'.

Contrib modules can step in and provide more complex logic for cases where there is no body field :)

vito_swat’s picture

I'd like to implement logic described in #4

yoroy’s picture

I've been wondering about this. It's weird, would like to see it fixed. #11 reads like it's more upgrade-from-D6-friendly?

ibex’s picture

I assume a proper fix must check all fields as proposed in #4.

I think it's worth having this problem fixed since readers could be (systematically) mislead in certain types of websites, e.g. posting of short news.

@vito_swat: Already a progress with your patch?

geerlingguy’s picture

Subscribe. Read more links have always been a thorn in my side, and it seems like they are still nowhere near as intuitive or helpful as they should be. The logic to check for whether all the fields are the same, etc. could be an extra performance-sapping procedure, unless the read_more flag can be cached, like it is in D6.

vito_swat’s picture

@ibex: patch is progressing slowly. It's more complicated than I expected, especially that I'm not that familiar with fields as I'd like to be.

vito_swat’s picture

Status: Active » Needs review
FileSize
4.02 KB

Here's first try. In general it's the implementation of algorithm given in #4

What the patch does:
1. Bring back node->readmore property in node_build_content(). Sets to false by default.
2. Checks if any field hidden in teaser mode is shown in full mode in field_default_view(). If so than it sets readmore property to true.
3. In text_field_formatter_view() it checks if any text field is shown as trimmed or as summary or trimmed then checks if trimmed version is the same as full version. If not it sets the readmore property to true. <- this mimics the D6 behavior for body field
4. Allow any field to set the readmore property by hook_field_formatter_view()
5. If any test will set the readmore property to true, Read more link will be shown.

Patch is lacking any test code as I'm not good at it. Please someone step in and help with it.

Status: Needs review » Needs work

The last submitted patch, better_read_more.patch, failed testing.

vito_swat’s picture

Status: Needs work » Needs review
FileSize
3.93 KB

corrected line endings for testbot.

rolfmeijer’s picture

subscribe

scito’s picture

Fields hook_field_formatter_view() implementations are responsible for correct readmore flagging with this solution. Each field must decide if two display types differ. If nothing is implemented, no "Read more" link will be shown. E.g. for tags field there will no "Read more" link be shown if the field is formatted as "Plain text" in the teaser and as "Link" in the full view. I think this is ok.

The patch looks good to me. But is this an API enhancement for fields? Do we need to document it somewhere?

I've made a minor white space improvement.

I've written several tests:

  1. Teaser and body are equal; without tag.
  2. Teaser and body are equal; with a tag.
  3. A field (tags) is hidden, but is empty.
  4. A field (tags) having a value is hidden.
  5. Teaser is trimmed.
  6. Summary is set.

Status: Needs review » Needs work

The last submitted patch, better_read_more_21_only_tests.patch, failed testing.

joachim’s picture

Given every field gets checked, I think some benchmarking might be needed.

geerlingguy’s picture

I second the benchmarking - this could be at least a minor performance drag. The 'read more' status of each node should be cached, and probably determined at the time of the node submission/update, as it was in D6.

joachim’s picture

Where was it stored in D6?

geerlingguy’s picture

Joachim - I presumed it was stored in the node or node_revisions table, but it looks like I'm wrong. Hrm... /me goes to check the logic of the $readmore... and realizes that the $readmore status is set in node_prepare(). Ah well.

vito_swat’s picture

Status: Needs work » Needs review

@joachim & geerlingguy
I'm not sure benchmarking will provide us any useful and meaningfull data here as the changes in the code are not that significant as you expect.

1. First of all not every field is checked but only fields hidden on the teaser (which is not so common in default profile there's no such case)
Performance hit: One field_get_display() and 2 ifs (if the build mode is teaser and field is hidden)
One if (eseif to be specific) in case the field is hidden but no other conditions apply.
No performance hit if field is shown (almost always the case)

2. The core will do another check for shown text field (for core node types only 1 additional check will be done).
Performance hit: one if.

Moreover teaser views are paged so I don't expect more than 50 node teases per page in very majority of cases. I don't think the performance hit if any (couple of ifs and no queries) will be noticeable to user.

geerlingguy’s picture

@vito_swat - if that's the case, seems okay. But if we had to introduce any extra data/queries, this would be a different story.

hansfn’s picture

Subscribe.

RumpledElf’s picture

Would be VERY happy if you can just disable the 'read more' by removing the teaser in the fields display. If you turn off teaser mode, the whole node displays and the 'read more' should go away too.

This is a very simple, basic thing that a lot of new users are going to want to turn off on a new site and it should be just a checkbox.

aza101’s picture

Guys, is there a simple way to fix this? Having the read more link on your home page when there is nothing more to read looks really bad. I am not a programmer, please can you provide a simple way to stop this happening even if it means totally turning off read more?

I don't mean to sound rude, but I really do not understand how the devlopers do not see how bad this makes drupal appear. If I hadn't already invested a lot of time and effort into learning drupal which includes the purchase of 2 books I would find another CMS. How many 'new users' is drupal losing to this? I am currrently using CSS display:none to hide it :s

mightaswell’s picture

subscribe

007pig’s picture

subscribe

bkmarsh’s picture

Which class did you apply the display:none to. I've tried a couple based on what I see in firebug and nothing seems to work. Thanks for any help you can give me!

j. ayen green’s picture

This is starting to seem like an engineering vs common sense issue, like "if you understood how razzaframs rely on dinglehoppers then you'd see there's a good reason why your car's fuel warning light comes on even when the tank is full."

RumpledElf’s picture

This is annoying enough that we wrote a module that gets around this *properly*, its sitting in the queue waiting review though.

joachim’s picture

@giraffian: what's the link for reviewing it?

Morn’s picture

This is Critical for me since it stops the upgrade of my sites from D6 to D7.
#21 works from me, but I think this should be a "Standard" functionality, not a module.

scito’s picture

@giraffian and @joachim: What's missing here is a review. Code and tests are available. According to me the fix of vito_swat is well written. However I cannot review my own tests. Maybe you could give it a try.

I would be happy to get this fixed in Drupal core, hopefully 7.1.

dlampel’s picture

subscribe

Bert386’s picture

subscribe

bryrock’s picture

subscribe

jodeygrist’s picture

I've just noticed this problem as well... I don't think it's actually a problem though, ya see I realised what it is doing when you promote something to the front page is simply trying to fit in what might be a lot of different posts which explains why it has to do teasers for that, even if for the content type you turn teaser off, I think you're really only setting it to display with an unlimited teaser length. It still displays as a teaser "style".

I think the key to static front pages, is not to promote anything to the front page, but to create your node as a basic page as you intended, however once you know the node address (ie node/1) go into configuration -> system -> default front page, and change that to be the node/1.

Once you do this, it will all display correctly as a single static page. This is obviously not a problem on any other page in the site because you can make the menu items link directly to nodes anyway so that's how a static site would be created.

Morn’s picture

@ 43, For someone starting with a new Site its not a big problem, but if you plan to migrate from D6 and have thousands of pages relaying on the correct handling of "read more" - as it was in D6 -, you have here a very critical issue.

j. ayen green’s picture

The point is that if the entire content of the node is displayed in the teaser, it shouldn't have a read more link because there's nothing more to read. After clicking 2, 3, 4 links and experiencing that, readers will cease and will miss content where there -is- something more to read.

vito_swat’s picture

Please test and review patch in #21. This is the only way it will get proper attention from the core commiters. Any more "subscribe" posts or complaining about the way D7 is working now will not help here.

@scito: thanks for the tests.

j. ayen green’s picture

shouldn't the tests patch pass?

david71’s picture

Hi.
I am a newbie to drupal.
Would really like to test your patch, but...
could someone please tell me how and where to implement the patch.

Just need a recipe. :-)

thx

rolfmeijer’s picture

david71, have you checked http://drupal.org/patch/apply?

joachim’s picture

david71’s picture

thank you for the link, will check it. Sorry guys, next time I´ll use the search field, promised.

Ok, just tried to apply a patch, but failed. Shame on me...

..then I found this video from Philbert with a cool workaround. Worked fine for me.

http://siteperspectives.com/node/3

Jamie Holly’s picture

I agree that this behavior isn't expected. It's very misleading, as a matter of fact. If there's a post on the front page, which is the full post, then there's a read more link and people click it thinking that there's something else. It leaves the impression that the site owner is just trying to increase page views. I have received quiet a few complaints from clients on this.

Until it can get patched, I have come up with a work around (albeit very ugly) using preprocess_node:

    if ($variables['content']['body'][0]['#markup'] != $variables['node']->body['und'][0]['safe_value']){
       unset($variables['content']['links']['node']['#links']['node-readmore']);
    }

It's probably (most likely) not the best way, but it does give the desired effect.

scito’s picture

shouldn't the tests patch pass?

No. If these tests fail without the patched code and succeed with the patch, then this shows that the "right thing" is tested.

@intoxination: Is there a reason for not using the patch #21? If so, this might help us improve the patch. Thanks anyway for sharing your version.

lloydpearsoniv’s picture

How about all of you use display suite & stop crying...lol
Display suite allows you to control all of your displays.

RumpledElf’s picture

If anyone wants to review the 'read more control' module its now got a sandbox project:

http://drupal.org/sandbox/Monochrome/1088582
And the original application: http://drupal.org/node/1056940

Needs reviewing by the community to become a full project.

joachim’s picture

@54, 55: this needs to be fixed in core, not polished over elsewhere.

RumpledElf’s picture

@joachim - couldn't agree more, but check the age of this thread. Painting over it with a patch or a module at least gets people able to convert to d7 if they want to.

joachim’s picture

Could all those people perhaps try the patch?

rolfmeijer’s picture

I’ve tried it. Is this the proper place to discuss it? There are no issues for sandboxed projects, right?

I encountered the following issues:

installing: there is no core version in the .info-file so it can not be enabled on the modules page (saying it is not a drupal 7.x module). I put it in myself (core = 7.x) and than it was ok.

running: setting the Read More Settings to “When Required” only worked if the fields I have (link an taxonomy) had the “Read More Ignores Field”-checkbox ticked. But than the read more-link was not displayed on all other content-types as well. Those content types did not have the link and taxonomy field.

When I have some more time, I will try to fiddle around with it a bit more. The design of the module seems well thought out. Although a variable to use in .tpl-files could be handy as well (good old $readmore).

update: Forget what I said about other content types.

joachim’s picture

> There are no issues for sandboxed projects, right?

Yes there are -- follow the link and the issue queue is on the RHS.

Can we keep discussion here on topic to the matter of fixing core please?

rolfmeijer’s picture

How could I’ve overlooked that? You’re right, I’m sorry, I will post it over there.

joachim’s picture

Component: node.module » field system
FileSize
11.44 KB

Okay here's a reroll with fixes for code style and a bit more detail in the comments.

> The patch looks good to me. But is this an API enhancement for fields? Do we need to document it somewhere?

Quite possibly.

This also needs review from FieldAPI people. It seems to me that field_default_view() is quite high up in the field system to be putting something specific to nodes and teaser view, but I've no idea if there's a suitable place to put it so we catch all fields on nodes -- I suspect there is not.

I'm reassigning to that component so it gets attention. If anyone following this thread is at DC Chicago, I suggest you try to buttonhole people who have worked on FieldAPI!

Jamie Holly’s picture

@scito - I plan on testing the patch on my personal site in the near future. I don't like doing patches on client sites, since that delays how long it takes me to update their sites to a newer version. I also wanted to put a simple fix out there, since this ticket is one of the results when you search Google about the problem and 90+% of Drupal users out there aren't comfortable or lack the knowledge of applying patches.

Something I do see that could cause problems (including in my fix) is that text_summary does run through _filter_htmlcorrector() (if set in the filter) after creating the summary. In theory, it shouldn't cause any problems, but that's one of those things that really needs tested out.

Having said that, maybe a better fix would be a change to text_summary's return value. It's very simple in that function to know if text is being trimmed or not, so returning an array might be better, ie:

return array('output' => $output, 'trimmed' => false);

In core, text_summary is only used in text.module, aggregator and node, so changing the return value wouldn't be too much work to fix. OTOH, this would be constitute a pretty big API change that could affect modules in contrib.

Another thing that could be an issue (and where I agree with @jaochim that this needs to be reviewed by the FieildAPI people and maybe even the entity people) is that we are altering $entity in a formatter_view (albeit just adding a new item). A workaround I see for that would be adding a new attribute in the $element[$delta] array, ie:

$element[$delta] = array('#markup' => $output, 'trimmed' => $trimmed); //$trimmed would come from the returned array of text_summary()

This would require more logic node_build_content, searching through each text field and looking for trimmed being set to true before deciding if a read more link should be attached.

Again - I defer to @jaochim's suggestion though of having the FieldAPI people take a look before going this route. Since what I'm suggesting actually involves an API change in text_summary, which I wouldn't doubt is being used in contrib, that might be enough to put this off to D8.

vito_swat’s picture

@intoxination

You seem only to focus on trimming text fields which is not the only case to show readmore link. Consider hidden fields or some custom field that need to alter this property. Proposed patch tries to do as much as possible without breaking existing API so it can be transparent to every module created.

Jamie Holly’s picture

@vito_swat - actually my method takes into consideration hidden fields more than the current patch. One problem is that this patch doesn't take into consideration node's with multiple body fields, in which the trimmed field might have restricted view access through hook_field_access. Hook_field_formatter_view is called regardless of the view op on hook_field_access, so that field that the current user doesn't have access to view still gets parsed and can set $entity->readmore. An example I can think of:

- You have an employee node type. It contains 2 body fields; general description and manager description.
- Manager description has limited view access to only those in the manager role.
- A manager puts a break or summary in the manager field for an employee, but the general description field doesn't have one.
- A regular employee views that node in teaser/trimmed mode. The manager description field still gets parsed through text_field_formatter_view and since it is trimmed, it will set $entity->readmore, hence giving that employee a read more, even though the field that is actually being truncated they can't even view.

(I just tested this by having field_access() return false on all views and it does as I described above. Not really sure why hook_formatter_view is called when a user doesn't have access to view that field, but that is the case.)

Again - this is a problem with setting readmore in $entity, especially when it happens so early in the field system. That's why it really needs reviewed by the FieldAPI people and even the entity people.

IMHO something should be done to make this take all that into consideration. The best way I can think of is for each field to be looped through in node_module. If #field_read_more (a new attribute set from my comment in #63) and #access == true, then the read more link is set.

The other plus to my idea is that other/non-core-text fields could utilize text_summary() and easily find out if the field has been truncated or not.

joachim’s picture

I rather like intoxination's suggestion of adding a key to the field contents.

However, it would make this into a system where multiple parts have to work together:

A. hook_field_formatter_view() implementations have an extra key they can return, #readmore (this better conveys the meaning that 'trimmed', I think. This should be set to TRUE if what the hook is returning is different in some way to the full version of the field's data -- eg, shorter text, different image style, fewer items. The hook should collate this itself over all its deltas, so for ex: foo_field_formatter_view() is currently outputting only deltas 1 and 2, but it has 4 items in all: it must set #readmore to TRUE.

B. Somewhere further up, the #readmores need to be collated.

C. Somewhere else again (?), hidden fields need to be taken into consideration,

Overall, $entity->readmore is TRUE if either B or C request it.

Is that a reasonable (albeit rough) summary?

@intoxination: you sound like you've played more with the innards of all this than me. Care to have a go at a patch?

Jamie Holly’s picture

That's pretty much it. I believe the work of B and C can pretty safely occur in node_build_content, especially given the now entity nature of nodes. If any other entities want to take advantage of the behavior, then they can simple mimic the same procedure. At least the work of handling the new key will already be in place (and I agree - readmore sounds good).

I'll work something up this coming week. I got a lot on my plate this weekend, but should be able to start on it Monday. I got a couple ideas floating around in the noggin also that should keep text_summary intact so that it doesn't break the API if any other modules use it. At least a "temporary" work around so we can maybe get this in D7 and then change the return value of text_summary in D8, before the API freeze occurs.

joachim’s picture

Status: Needs review » Needs work

Great! I look forward to seeing it. In the meantime, changing status back to 'needs work'.

Jamie Holly’s picture

Status: Needs work » Needs review
FileSize
7.7 KB

Here's go number one at this. Keeping with my idea to not actually break the API of text_summary, it made that function a little more ugly. I got some commenting in there, but not much yet. I figured we can get people testing it at least.

Anonymous’s picture

Subscribing. This is a deal-breaker issue...

joachim’s picture

Status: Needs review » Needs work

Thanks! I think it's potentially simpler than the earlier approach, but I've a few questions...

First though, you're missing the tests scito wrote -- those need to be in.

Second, I don't see where you're accounting for fields simply hidden on teaser view.

+++ b/modules/field/modules/text/text.module
@@ -341,10 +345,13 @@ function _text_sanitize($instance, $langcode, $item, $column) {
+ * @param $return_status
+ *   Set to true if you would like an array returned, including 'text' and
+ *   'trimmed'. If trimming occurs, array key trimmed will be set to true.
  * @return
- *   The generated summary.
+ *   The generated summary or an array containing the keys summary and trimmed if $return_status is true.
  */
-function text_summary($text, $format = NULL, $size = NULL) {
+function text_summary($text, $format = NULL, $size = NULL, $return_status = FALSE) {

This kind of change really isn't going to fly, I'm afraid. Even if we were still in development, a function that changes its return is a bit iffy :/

Instead, what about a wrapper to this which merely passes on the $text and on its return, check if there's a difference.

So:

function needs_a_good_name($text, $otherparams...) {
 $summary = text_summary($text, $otherparams...);
 if ($summary == $text) {
  // Nothing changed
  $trimmed = FALSE:
  }
  else {
   // Summary is shorter.
  $trimmed = TRUE;
  }
  // Return an array accordingly.
}
+++ b/modules/node/node.module
@@ -1370,15 +1371,32 @@ function node_build_content($node, $view_mode = 'full', $langcode = NULL) {
+    foreach ($node->content as $item){
+      if (isset($item['#access']) && $item['#access'] == 1){
+        foreach ($item as $key=>$value){
+          // check to see if the key is a property or child. We want children only here
+          if ($key === '' || $key[0] !== '#') {
+            if (isset($value['#readmore']) && $value['#readmore'] == TRUE){

I would put this logic in a helper function in field module which returns TRUE if the entity it's passed is in a 'read_more' state. This would allow modules other than node to use this too if they wish -- it makes sense too, given it's the fieldAPI modules that put in the #readmore in the first place.

This also saves you the ugly 'continue 2'! :)

Finally, to anyone making patches -- please take time to check your code style, eg things like 'TRUE' rather than 'true', and how to indent and bracket. If you're not entirely familiar with the Drupal coding guidelines, I strongly recommend you use Coder module to review your code before rolling the patch -- it saves everybody time :)

Powered by Dreditor.

Jamie Holly’s picture

Yeah I haven't done the tests yet. Just wanted to get a rough patch out there before getting to involved in it.

I'm not really sold on the hidden fields. First off, fields not shown on the "teaser" view shouldn't have summaries or breaks set in them, since they would never be used. If we decide that a field shown in full view, but not shown in teaser view should trigger a readmore, then which fields? Text only or all of them? I can see that leading to other issues also, such as people who put an attachments list on their posts, but that only shows on the full view and they don't want a readmore for it.

If you look, by default it doesn't alter the return value, only if the 4th parameter - $return_status - is set to true, does it then change to return the result array. That's a new parameter I added in to keep backwards compatibility with the function. It might be worth going back to the string compare equality check though, as in the first patch. There still might be some weird scenarios where a string isn't actually truncated, but would not be equal to the original string with the truncated string running through _filter_htmlcorrector() (if set in the filter), but those should be very, very fringe cases and I think the same would even occur in D6.

Putting the readmore check in a helper function is a great idea. I think the biggest question is if it should be in filter.module or text.module. This is where getting some input from the FieldAPI people would be nice.

And yeah I noticed the lowercase true and false's. I really need to get coder reinstalled on here. If only we could make a patch to add more hours to the day lol.

joachim’s picture

> If we decide that a field shown in full view, but not shown in teaser view should trigger a readmore, then which fields?

All of them. Read more means 'If you click this link you will see more stuff than you can see right now'. That includes longer text fields, more items from a field, hidden fields. Not sure about bigger pictures though -- but that's a bikeshed I think :)

> but that only shows on the full view and they don't want a readmore for it.

Then it'll be up to them to customize it with the theme or alter hooks.

> If you look, by default it doesn't alter the return value, only if the 4th parameter - $return_status - is set to true, does it then change to return the result array. That's a new parameter I added in to keep backwards compatibility with the function.

Yeah... that's the problem -- the code has to jump through all these hoops to figure out what kind of thing it should return. That really is ugly, sorry.

> I think the biggest question is if it should be in filter.module or text.module.

Hmm good question. I'd say text module.

Jamie Holly’s picture

The hidden field issue is going to have a serious performance impact though. The only way to know if there are fields showing on full view, but not teaser view is to also generate a full view, since you have to take into consideration optional fields that might not be filled out (hence all fields will have to be loaded, their data calculated and their #access checked).

I'm afraid readmore is pretty much going to have to pertain to fields only that are available in teaser view, or we are going to have to stick with the current behavior as-is. I would love to see if there's an issue that discussed this original change in D7 to see why it went this way. I haven't been able to find one.

joachim’s picture

Oh I see what you mean -- this case:

node X has field Foo on it, and field Foo happens to be set to hidden on teaser AND on node X is empty anyway.

We don't want field Foo to request a readmore in this case, as it has nothing to show.

Would the $node object actually hold the $node->field_foo data, or is that cleverly skipped at the node_load() stage?

Jamie Holly’s picture

The fields are loaded in the entity loader (node_load()), but the field_access checks aren't done until field_attach_view, which is in node_build_content.

Once scenario I really see that this could break in is with OG. I have a D7 site running OG and I have the group field showing on the full view, but in field access it's disabled for everyone (that way it only shows to user 1 for debugging). Since that field is there and the access check is never done, every group post would show a readmore because of that field that is only visible to user 1.

Jamie Holly’s picture

Here's another go at the patch. I put the tests in this time, using mostly the ones @joachim wrote since the test outcome is the same (just dropped the hidden fields test).

- I went back to just doing a string equality that checks for readmore and then sets the #readmore attribute on the return array.
- Moved the checking of #readmore on renderable fields to a helper function in text.module (text_has_readmore()).

pillarsdotnet’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, fix-readmore-link-823380-78.patch, failed testing.

joachim’s picture

> mostly the ones @joachim wrote

BTW -- I didn't write those tests, they were from an earlier patch I rerolled and did a bit of work on.

+++ b/modules/field/modules/text/text.module
@@ -445,6 +455,37 @@ function text_summary($text, $format = NULL, $size = NULL) {
+function text_has_readmore($elements){

It's the whole node rather than just the text we're asking about right?

Also, it should read_more, not readmore, throughout -- note the way in Drupal we say pre_render and don't mashwordstogether ;)

So node_has_read_more(). Or entity_has_read_more().
I don't think it belongs in text module either.

+++ b/modules/field/modules/text/text.module
@@ -445,6 +455,37 @@ function text_summary($text, $format = NULL, $size = NULL) {
+      foreach ($element as $key=>$value){

Don't use $key => $value unless you can possibly avoid it. Also, if you only want children, use element_children(). And watch the spacing ;)

+++ b/modules/field/modules/text/text.module
@@ -445,6 +455,37 @@ function text_summary($text, $format = NULL, $size = NULL) {
+        // check to see if the key is a property or child. We want children only here

Capitalize the first word of the sentence; end with a full stop; line break at 80 chars.

This is nitpicky I know but a patch will NOT be committed to core unless it passes these standards -- it won't even get to RTBC. Please please try to follow them -- otherwise it just means another iteration of work on it. It's quicker if the patch author follows them, rather than the reviewer have to go through and pick up on them all.

+++ b/modules/node/node.test
@@ -2146,3 +2146,141 @@ class NodeTokenReplaceTestCase extends DrupalWebTestCase {
+    $this->assertNoText('Read more', t('"Read more" does not appear in the default listing.'));

These could do with more detail. If I read a test report, I wouldn't know what sort of test had failed and why -- as I currently am doing with the testbot's latest result...

Also, your patch seems to include the patch... :/

Powered by Dreditor.

bfroehle’s picture

Also, I suspect the implementation will need to be recursive. Perhaps something like this (where I've omitted the docblock in the name of space):


function node_has_read_more($elements) {
  // Early-return if the user does not have access.
  if (empty($elements) || (isset($elements['#access']) && !$elements['#access'])) {
    return FALSE;
  }

  // Return if #read_more is set on this element.
  if (!empty($elements['#read_more'])) {
    return TRUE;
  }

  // Iterate through children.
  foreach (element_children($elements) as $key) {
    if (node_has_read_more($elements[$key])) {
      // A child element has #read_more set to TRUE.
      return TRUE;
    }
  }

  // Neither this element, nor any child elements had #read_more set.
  return FALSE;
}
Jamie Holly’s picture

If someone else wants to take a go at this, then go ahead. I'm not really going to have anytime for at least the next week, as I'm heading out of town.

tomcatuk’s picture

Be nice to be able to quite simply do without them. Please don't anyone suggest display:none.

fuzzy76’s picture

Subscribing. This bug is embarassing for D7 :-/

scito’s picture

I would love to see if there's an issue that discussed this original change in D7 to see why it went this way. I haven't been able to find one.

#372743: Body and teaser as fields

Jamie Holly’s picture

I'm back and here's another go with the following:

- Changed function to field_has_read_more and moved to field.module and made it a recursive function.

I'm not really sure about readmore -v- read_more. Going back throughout Drupal history it has always been referred to as readmore. Also going from #82, we are in D7 and entities now. Calling it node_has_read_more really isn't accurate, as different entities could utilize this (ie: users or comments). Also placing it in field.module seems more appropriate as other fields could use this down the road.

I've tested it out somewhat and it seems to be working good. More testing will be needed though.

geerlingguy’s picture

Status: Needs work » Needs review

We'll see how the tests go, too...

pillarsdotnet’s picture

Jamie Holly’s picture

It actually might not be a bad idea to merge both issues. There shouldn't be any conflicts, but given the extremely close relation, I could see something popping up down the road.

vito_swat’s picture

I propose to add another test to the case -> check if some text here <!--break--> will trigger readmore. It should not.

erdembey’s picture

subscribe

bryancasler’s picture

subscribe

bryancasler’s picture

Patch #89 is working great for me so far

pillarsdotnet’s picture

Version: 7.x-dev » 8.x-dev
Issue tags: +Needs backport to D7

Bumping and tagging as per standard policy.

pillarsdotnet’s picture

You can help this issue by posting a review:

  • Decide whether all code and comments comply with Drupal coding standards.

  • Decide whether any included tests are necessary and sufficient.

  • Decide whether the patch actually solves the problem. There should be a reproducible test where the current code fails and the patched code succeeds.

A review that affirms success in all of the above should also:

  • Change the issue status from "Needs Review" to "Reviewed and Tested By the Community".

Otherwise, the review should:

  • Explain what is wrong with the proposed patch and/or supply a corrections to it.

  • Change the issue status from "Needs Review" to "Needs Work".

David4514’s picture

Patch in #89 is working great. I hope this is moved into D7 Core.

bryancasler’s picture

Patch #89 has been working well for me

Morn’s picture

Patch #89 has been working well for me, it should be set to "Reviewed and Tested By the Community"

pillarsdotnet’s picture

Status: Needs review » Reviewed & tested by the community
trobey’s picture

I installed a clean version of Drupal 8.x-dev. Then I created a test article. The Read more link appears on the front page even though the entire article (one word) appears. I applied the patch. The Read more link no longer appears. Reviewing the code I only found a missing space between a function and the open bracket:

function field_has_read_more($elements){

I did not see any other problems with coding standards.

From the discussion and a quick look at the patch it looks like the tests supplied are sufficient.

pillarsdotnet’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
28.61 KB
pillarsdotnet’s picture

Bah. Fixed that missing space.

Status: Needs review » Needs work

The last submitted patch, Better-read_more-823380-103.patch, failed testing.

pillarsdotnet’s picture

Status: Needs work » Needs review
FileSize
24.81 KB

(sigh) trying again, minus my custom changes to the standard profile...

Status: Needs review » Needs work
Issue tags: -Needs backport to D7

The last submitted patch, Better-read_more-823380-105.patch, failed testing.

Smokie’s picture

Status: Needs work » Needs review
Issue tags: +Needs backport to D7

#19: better_read_more.patch queued for re-testing.

pillarsdotnet’s picture

pillarsdotnet’s picture

Ran coder_review and updated as per its recommendations.

Status: Needs review » Needs work

The last submitted patch, better_read_more-823380-109.patch, failed testing.

pillarsdotnet’s picture

Status: Needs work » Needs review
FileSize
34.48 KB

(sigh) The description for text_summary() says that it produces trimmed output, yet actually doing so breaks stuff all over the place.

pillarsdotnet’s picture

Status: Needs review » Reviewed & tested by the community

Marking RTBC as before.
/me ducks!

sun’s picture

Status: Reviewed & tested by the community » Needs work

The original patch in #87 was not related at all to #221257: text_summary() should output valid HTML and Unicode text, and not count markup characters as part of the text length, so I've no clue why this issue got extremely hi-jacked by merging another major issue into this one.

For this patch to be remotely reviewable and committable, we need to go back to the patch in #87, either directly, or by extracting the relevant parts from the latest patch (in case there have been any changes).

pillarsdotnet’s picture

Status: Needs review » Needs work
FileSize
14.71 KB

Re-rolled as requested, but the two patches are related; they do overlap; they do break each other; and they were merged at the suggestion of intoxination in #823380-90: Read More link is always visible on teaser..

pillarsdotnet’s picture

Status: Needs work » Needs review
pillarsdotnet’s picture

Status: Needs work » Needs review
FileSize
5.1 KB
14.08 KB

Removed some debugging code I had inadvertently left in.

Also attaching an interdiff for completeness.

pillarsdotnet’s picture

Status: Needs review » Reviewed & tested by the community

RTBC as before, again.

sun’s picture

Status: Reviewed & tested by the community » Needs review

This patch requires an in-depth review and sign-off from entity/field system maintainers.

The approach taken is interesting, but as well debatable on its own. It looks like it hard-codes even more logic for the 'teaser' view mode. That might very well be all we can do for D7, but I'm not sure.

I'm also not sure whether this patch possibly has a negative impact on performance, or whether the recursion into renderable elements happens within a cached code path.

Lastly, the patch contains a lot of unrelated (and partially wrong) code clean-ups. It would be helpful to remove those to facilitate more focused reviews and to make faster progress.

pillarsdotnet’s picture

@sun

Lastly, the patch contains a lot of unrelated (and partially wrong) code clean-ups.

Can you point to at least one of the "partially wrong" bits?

yched’s picture

Subscribe for now. Are there any specific comments I should read to get a summary of the discussion leading to the approach taken in the patch ?

This is basically leaving it to formatters to say "I'm -probably- displaying a shortened version of what is -probably- available on the 'full' view mode". That's a somewhat reasonable assumption for the 'trimmed' and 'summary_or_trimmed' formatters for text fields, but that does introduce some one-off logic about *node* *teasers* into some entity-and-view-mode-agnostic formatter code.

At the same time, it leaves out the case where a 'read more' link would make sense just because the full node displays a larger/different set of fields. Someone rightfully pointed that those cases would be fairly difficult to detect, and IIRC that's the main reason why the 'Body as field' patch just made every teaser get a 'read more' link. 'Read more' is a notion coming straight from the pre-CCK era, and is difficult to map to a fieldable world...

This being said, on the plus side of the patch, the #read_more property makes it easier to provide 3rd party logic.

Still pondering...

pillarsdotnet’s picture

#116: better_read_more-823380-116.patch queued for re-testing.

Morn’s picture

Version: 8.x-dev » 7.2

Patch #116 doesn't work with following code under 7.2 (worked under 7.0, teaser cut option is 2400 chars)

<table  border="1" width="100%">
	<tbody>
		<tr valign="top">
			<td style="border-right: 1px solid;">
				<p>
					Die Viteritas GmbH ist eine bankenunabh&auml;ngige Servicegesellschaft, welche sich auf die professionelle Verwaltung von Kundenkonten (Managed Accounts) mit diskretion&auml;ren und automatisierten B&ouml;rsen-Handelssystemen spezialisiert hat.</p>
				<p>
					Wir sind ein Team von erfahrenen und professionellen H&auml;ndlern mit Zertifizierung als Technische Analysten mit Spezialisierung auf den Bereich Forex-, Rohstoff- und CFD Trading. Unser Ziel ist das Erreichen einer langfristig, &uuml;berdurchschnittlich hohen Performance f&uuml;r unsere Kunden im aktuell volatilen Marktumfeld.</p>
				<p>
					Investoren k&ouml;nnen &uuml;ber ein Managed Account (verwaltetes Depotkonto) investieren. Dabei vermitteln wir die Handelskonten bei einem Broker und unterst&uuml;tzen unsere Kunden bei der Kontoer&ouml;ffnung.</p>
				<p>
					&nbsp;</p>
				<ul style="list-style-type: circle;">
					<li >	High Quality Papiere</li>
					<li >
						Transparente Strategien</li>
					<li>
						Erleben sie unsere Trading-Strategien live</li>
				</ul>
				
			</td>
			<td valign="top" width="30%">
				<span style="color: rgb(169, 169, 169);">Rechtlicher Hinweis: Die Angaben auf unserer Homepage stellen keine Anlageberatung dar, sondern dienen ausschliesslich der Beschreibung einzelner ausgew&auml;hlter Aspekte des dargestellten Produkts. Dieses Angebot richtet sich an Anleger die in der Schweiz wohnhaft bzw. domiziliert sind.</span></td>
		</tr>
	</tbody>
</table>

Morn’s picture

Version: 8.x-dev » 7.2
Assigned: pillarsdotnet » Unassigned

sorry for #122, Patch worked after setting the Teaser cut size to 3400 chars.

pillarsdotnet’s picture

Version: 7.2 » 8.x-dev
Assigned: Unassigned » pillarsdotnet

The patch in #116 is not against 7.2; it is against 8.x.

And you haven't given enough information to identify a problem or code a fix.

Given the above data in the body of a node, and a teaser length of 2400 characters, please provide your expected output from text_summary. (In other words, what would the teaser contain?)

With that minimal information, I can write a test. If the test fails, I can fix the code so that the test passes.

Morn’s picture

Version: 7.2 » 8.x-dev
Assigned: Unassigned » pillarsdotnet

@ #124 - the teaser is empty, all the html code is in the body, but as I stated in #123, after setting the "Trim length" to 3400 (2400 works also) there was no problem - The "read more" Link didn't appear after
applying this patch (even if it is for 8.x).

pillarsdotnet’s picture

So ... I'm confused. Is there a problem, or not?

Morn’s picture

There is no problem :-)

Kamal Prasad’s picture

Morn’s picture

I am confused, what should I apply for Drupla 7?
Patch of #128 oder the "better ..." patch of #116 ?
or nothing, since its for Version 8?

pillarsdotnet’s picture

I'll re-roll patches shortly.

pillarsdotnet’s picture

Patches for 8.x and 7.x.

@Morn and other d7 users should apply better_read_more-221257+823380-131-d7.patch to a 7.x git checkout (not the same as a release version).

pillarsdotnet’s picture

Assigned: pillarsdotnet » Unassigned

Unassigning myself as I've really done all I can do at this point.

Opened alternative proposal: #1185936: Rename the "Read more" link to "View on separate page"

aspilicious’s picture

Status: Needs review » Needs work
+++ b/modules/node/node.testundefined
@@ -2146,3 +2146,141 @@ class NodeTokenReplaceTestCase extends DrupalWebTestCase {
+}
\ No newline at end of file
-- 

Add a newline

Powered by Dreditor.

aspilicious’s picture

Status: Needs work » Needs review

No need to put needs work for only that :)

metamorphmuses’s picture

Version: 8.x-dev » 7.0
Category: bug » feature

It's unfathomable and incredibly short-sighted that the functionality of the $readmore variable was deleted in D7. I am a designer, not a coder; this GIT system looks way too hairy. I will try my best to spoof how the system worked in D6 by creating a field so that I can create an ad hoc link on a node-by-node basis, as needed.

geerlingguy’s picture

Version: 7.0 » 8.x-dev
Category: feature » bug

This is being worked on. And, since its going to require review before getting into 8.x, and then more review before being considered again for 7.x, it would be best if you could help review this or offer constructive suggestions for improving the way the read more link works.

While it does stink that the read more system works so poorly in drupal 7, things will get better... And there are definitely ways to work around this situation.

metamorphmuses’s picture

Version: 8.x-dev » 7.0

My suggestion is to restore the functionality of the $readmore variable. Whatever the code was underlying that variable in D6 and earlier, I'd like to see it exposed for all to see. I have searched and searched, to no avail. All I see is "$readmore: Flags true if the teaser content of the node cannot hold the main body content," in http://api.drupal.org/api/drupal/modules--node--node.tpl.php, under Node status variables.

It seems to be that testing for, in shorthand, $teaser != $page is a part of the full picture, but other factors are at play, as others have pointed out. So, the question is, just how did that variable flag as true?

pillarsdotnet’s picture

Version: 7.0 » 8.x-dev

If metamorphmuses asks nicely and specifies which version of Drupal he is using, I might be persuaded to roll him a separate patch. Alternatively, he could learn to roll his own.

metamorphmuses’s picture

Version: 8.x-dev » 7.2
Category: bug » feature

pillarsdotnet, I appreciate that you and others have been working to get a patch done. My ire is directed at the collective decision to remove functionality in D7 that existed in D6; my attitude is that successive versions should always augment, and only deprecate when there is a clear consensus that a particular feature is obsolete (e.g. the deprecation of HTML frames, although even those are still supported).

As to the patches that rely on GIT, if I decide they are worth trying, I will learn how to go that route. Thank you for offering up assistance.

Like I stated above, I am going to try to implement a read more field that can be applied to an individual node as needed.

pillarsdotnet’s picture

Version: 7.2 » 8.x-dev
Jamie Holly’s picture

Metamorphmuses:

I have a simple block of code at http://drupal.org/node/823380#comment-4191332 that you can use to tell if a node is showing truncated text or not. You can easily put it in a hook_preprocess_node in the template file.

As far as the version, changing this back to 7 makes it much less likely it will get attention from the core developers. Development is currently on D8 and the practice is for items like this to be made available in the version on current development and then backported to the current release.

gpk’s picture

The read more link doesn't work properly in 6.x either. See #201854: "Read more" link sometimes shown when it shouldn't be, or not shown when it should.

Morn’s picture

The Patch #131 for D7 works also for 7.4

pgough’s picture

Does patch #131 resolve the problem of the read more link displaying on node teasers that have more information to be displayed? If so, where do you apply the patch? I am enquiring for drupal 7.

Thanks

Morn’s picture

@144, yes, but it could be that you have to adjust the the teaser length for your content types

pgough’s picture

do you apply this to the node module?

pgough’s picture

do you apply this to the node module?

Morn’s picture

I used Git bash for windows and applied the better_read_more-221257+823380-131-d7.patch to Drupal 7.4
Put the patch file in your downloaded d7 Main diretory and issue (cd to the directory) with git bash
git apply --verbose *.patch

Morn’s picture

The Patch #131 for D7 works also for 7.7 (when will it be integrated in D7?)

pillarsdotnet’s picture

@Morn

when will it be integrated in D7?

Probably never.

The problem is that, since an arbitrary number of fields can be attached to any node type, and each field can individually be turned on or off for the teaser display, there is no easy way to test whether the teaser is equivalent to the full node. The patch in #131 merely tests whether all the "text_with_summary" fields have a summary that is equal to their full content. While this is probably useful for many users who are merely seeking to upgrade a D6 site to D7, the whole approach needs to be re-thought and re-worked to become core-worthy.

One approach is to rename the "Read more" text to something more descriptive.
See #1185936: Rename the "Read more" link to "View on separate page"

joachim’s picture

> The problem is that, since an arbitrary number of fields can be attached to any node type, and each field can individually be turned on or off for the teaser display, there is no easy way to test whether the teaser is equivalent to the full node.

Of course there is -- if the field is not being shown on the teaser, then the teaser is not equivalent to the full node.

I've not been following this patch for a while, but I thought it was doing that?

Morn’s picture

Without this patch, the amount of time needed for the Upgrade D6->D7 increases a lot.
Comparing with other CMS systems the drupal core upgrades are an horror for me.
Specially when my costumers dodn't like the Option "View on the separate page"

richardtmorgan’s picture

Re. Comment #52: the condition in the first line should be '==' not '!='
i.e.:

if ($variables['content']['body'][0]['#markup'] == $variables['node']->body['und'][0]['safe_value']){
   unset($variables['content']['links']['node']['#links']['node-readmore']);
}

Many thanks for this - I didn't want to run a patch against core, and dropping this into my node preprocess function in template.php worked great for me.

bryancasler’s picture

bump

yoroy’s picture

Issue tags: +summary

Seems to me this is a bug and was accidently changed to feature request.
At 150+ comments in, I think this issue could do with a summary on the approach taken for the proposed solution to give reviewers an easier way to get up to speed.

davedpss’s picture

Title: Read More link is always visible on teaser » Read More link - Can it be disabled?
Version: 8.x-dev » 6.21

Is there a simple (or not simple) way to disable the read more link on teasers? Whether on the front page or not? Thanks.

pillarsdotnet’s picture

Title: Read More link - Can it be disabled? » Read More link is always visible on teaser.
Version: 6.21 » 8.x-dev

This is not a support forum.

joachim’s picture

Issue summary: View changes

added a summary

joachim’s picture

Category: feature » bug

I agree with yoroy -- this is a bug, because it's a regression from D6.

Added a summary.

joachim’s picture

Issue summary: View changes

oops. messed it up. editing the OP for a summary is a total crack way to do it and I hate having to write log messages anyway

pillarsdotnet’s picture

I was adding one at the same time. Hopefully, I successfully merged our separate efforts.

pillarsdotnet’s picture

Re-rolled #131, removing unrelated clean-ups.

Status: Needs review » Needs work

The last submitted patch, better_read_more-823380-160.patch, failed testing.

pillarsdotnet’s picture

Status: Needs work » Needs review
FileSize
13.89 KB

(sigh) The new comment tests added by #983632: New comment marker does not work are unnecessarily testing for the existence of the "Read more" link and failing when it does not exist.

Commented out the failing tests.

joachim’s picture

@#159: yup, combined summary looks great :)

Status: Needs review » Needs work

The last submitted patch, better_read_more-823380-162.patch, failed testing.

pillarsdotnet’s picture

Status: Needs work » Needs review
FileSize
12.16 KB

I give up. There are too many tests that depend on the existence of the "Read more" link. How about we hide it via CSS instead of removing it altogether?

Status: Needs review » Needs work

The last submitted patch, better_read_more-823380-165.patch, failed testing.

pillarsdotnet’s picture

Status: Needs work » Needs review
FileSize
12.46 KB

Use xpath queries to check for class existence / nonexistence in the link.

pillarsdotnet’s picture

Issue summary: View changes

Crosspost with hopefully a slightly improved summary.

pillarsdotnet’s picture

And as I read the docs, I realize that it should have been 'element-hidden' rather than 'element-invisible'.

joachim’s picture

> How about we hide it via CSS instead of removing it altogether?

I thought you were kidding when I read that but I see you've added it to the summary.

That really doesn't seem like the best way... is it that hairy? :(

Anonymous’s picture

> How about we hide it via CSS instead of removing it altogether?

Reputedly this looks spammy to search engines. If that is true, having your front page take an SEO hit is not good.

pillarsdotnet’s picture

That really doesn't seem like the best way... is it that hairy? :(

Here's the patch and interdiff. Judge for yourself.

Reputedly this looks spammy to search engines.

Please supply a reference to support your assertion. Reputed by whom?

If that is true, having your front page take an SEO hit is not good.

The .element-hidden class is used for collapsible fieldsets, and the .element-invisible class is used to display alternative text to screen-readers. I've never heard of them being SEO-unfriendly. There's a lot of Drupal code that uses these features:

bobvin@bowie:~/www/8.x$ git checkout 8.x
Switched to branch '8.x'
bobvin@bowie:~/www/8.x$ egrep -r 'element-(hidden|invisible)' includes modules profiles themes | wc -l
51

Fifty-one times in D8 core. And five more added by this patch:

bobvin@bowie:~/www/8.x$ git checkout 823380
Switched to branch '823380'
bobvin@bowie:~/www/8.x$ egrep -r 'element-(hidden|invisible)' includes modules profiles themes | wc -l
56
pillarsdotnet’s picture

Dunno how that extra semicolon got there.

pillarsdotnet’s picture

Issue summary: View changes

Describe the 'element-hidden' strategy.

Status: Needs review » Needs work

The last submitted patch, better_read_more-823380-171.patch, failed testing.

pillarsdotnet’s picture

Status: Needs work » Needs review
FileSize
10.41 KB

Weird. Installs locally; tests pass. Testbot problems? Trying again, and also removing the trim() calls added for compatibility with #221257: text_summary() should output valid HTML and Unicode text, and not count markup characters as part of the text length.

joachim’s picture

> The .element-hidden class is used for collapsible fieldsets, and the .element-invisible class is used to display alternative text to screen-readers.

Yes, and those are both good cases. When fieldsets are collapsed they are hidden, and screen readers need additional context that in visual output is superflous.

This is hiding something so our tests still pass... doesn't smell good to me at all. It seems rather akin to the times when a themer I'm working with hides something with CSS rather than properly using the theme to remove its actual output.

pillarsdotnet’s picture

Issue summary: View changes

Wordsmithing.

pillarsdotnet’s picture

Status: Needs review » Postponed

Open up a separate issue to clean-up and/or remove the tests that assume the "Read more" link is always present.

Marking this issue "postponed" until then.

EDIT: updated summary to reflect the 'postponed' status.

pillarsdotnet’s picture

Priority: Major » Normal

We shouldn't have major bug reports in a 'postponed' status. Downgrading.

joachim’s picture

Priority: Normal » Major

It being postponed doesn't change its severity!

I do appreciate you feel burned out by all these failing tests though :(

Anonymous’s picture

Googling 'seo css hidden links' turns up lots of pages that say Google thinks CSS-hidden links are spammy. Random examples: http://www.angelseo.co.uk/seo/black-hat/whats-wrong-with-hidden-texthidd... http://www.stonetemple.com/articles/css-and-seo.shtml . This may be an urban legend, but it is at least a wide-spread one.

> We shouldn't have major bug reports in a 'postponed' status. Downgrading.

This makes no sense (to me). Major is a level of severity. Postponing it does not decrease its severity.

Maybe the severity isn't major, but that's a separate argument.

(I'd say it is major. It's a major end-user experience WTF to click on a "read more" link and not be given anything more to read.)

pillarsdotnet’s picture

Well, unless one of you is willing to open an issue to rewrite all those patches, it's going to be "won't fix".

Meanwhile, this issue is blocking other improvements to Drupal core.

See Drupal core code freeze, code thaw, issue count thresholds.

It's a major end-user experience WTF to click on a "read more" link and not be given anything more to read.)

The user does get something more to read, or at least something different. The teaser display is rendered differently from the full node, even if no text was trimmed and no fields were removed.

That's why I opened #1185936: Rename the "Read more" link to "View on separate page"

Anonymous’s picture

OK, I have opened #1300568: Fix tests that wrongly assume all teasers have a Read more link.

I greatly appreciate the hard work you have done on this issue. I am sorry it is so frustrating.

I'm afraid I don't think #1185936: Rename the "Read more" link to "View on separate page" is a good solution, for the reasons given by TR in comment #3 on that issue.

Anonymous’s picture

Issue summary: View changes

Added dependency on removal of bogus tests.

pillarsdotnet’s picture

@#181 by a1tsal

OK, I have opened #1300568: Fix tests that wrongly assume all teasers have a Read more link

Great. Now someone should (at least) identify the files and line-numbers where those tests are located.
(Posting here rather than there because I do not want to subscribe to that issue.)

John_B’s picture

I hestitate to jump in with something which seem a distraction, but a useful interim solution for D7, may be a contrib module adding a 'no read more link' check-box field to each content type, and removing the Read More link if it is checked?

pillarsdotnet’s picture

@#183 by John_B:

a contrib module adding a 'no read more link' check-box field

I look forward to reviewing your project application.

joachim’s picture

In response to some of the recent comments:

1. Changing the status of a bug to reduce the blocking count is not the way to manage our bugs, and makes the blocking count meaningless. If this bug blocks ongoing development, then so be it: that means that ongoing core development is here on this bug.

2. I've not looked at the code since pillarsdotnet flagged this, but it seems to me that the tests should be fixed or ripped out as part of this patch? I'm not sure we need a separate issue to fix or remove those tests, though I can see that having an issue to concentrate on just those might help simplify the work.

3. There is already a sandbox module for fixing this problem. I gave a -1 its promotion to full project because making a contrib module to work around a problem in core is not the way to do things. It has been done before, but that's no reason to do it again.

pillarsdotnet’s picture

Before you rip out tests that someone else wrote, you'd better coordinate with whoever wrote and/or approved those tests.

We have tests for a reason -- to reduce the possibility of regressions. Somewhere, somehow, there was a bug which was fixed, and a test was written to make sure the bug stays fixed. You rip out that test without a deep understanding of why it's there and you destroy the whole quality assurance system.

It would probably take me four to six hours to research (using git blame and reading through issues and patches) exactly why each and every one of those tests were written. (Although I'm sure some core developers could tell you from memory, good luck getting their attention!)

At that point, we still would not have buy-in from the core developers, (see #118 above), so not the resultant patch would be even less likely to be accepted.

Which makes this entire issue very nearly a "won't fix".

Really, we're at comment #186 and there has not been a single positive review from anybody in MAINTAINERS.txt -- this issue is doomed.
EDIT: Retracted; see #188

John_B’s picture

@joachim Thanks for the heads up on the workaround module whose application you rejected. You probably mean Read More Control.

A contrib module only as a workaround for a core problem may be inelegant. However, it could save hundreds of developers delivering thousands of Drupal sites to end users most of which have this (superficially simple) problem which makes Drupal look bad. Maybe the project's application should be reconsidered. I am certainly going to try the sandbox module.

pillarsdotnet’s picture

Sent contact emails to catch, Frando, ysched, and bjaspan as follows:

As an Entity/Field System maintainer, could you please look at:

Issue #823380: Read more link is always visible on teaser

It is currently stalled because it lacks "an in-depth review and sign-off from entity/field system maintainers." and also because the generally agreed-upon solution conflicts with tests that assume the "Read more" link is always present.

See related: #1300568: Fix tests that wrongly assume all teasers have a Read more link.

Even a decision of "closed (won't fix)" would be better than nothing, at this point.

pillarsdotnet’s picture

Status: Postponed » Needs review
FileSize
10.44 KB

Think I found the problem with the xpath query in #174. Re-rolling

pillarsdotnet’s picture

This is essentially the patch from #162 combined with the one from #1300568-4: Fix tests that wrongly assume all teasers have a Read more link

pillarsdotnet’s picture

Messed up the patch in #190 -- here's another try:

pillarsdotnet’s picture

Another try at the element_hidden approach.

pillarsdotnet’s picture

And this is the alternative "rip out the failing test" approach.

Status: Needs review » Needs work

The last submitted patch, better_read_more-823380+1300568-193.patch, failed testing.

pillarsdotnet’s picture

Status: Needs work » Needs review
FileSize
13.42 KB

Re-rolled.

Status: Needs review » Needs work

The last submitted patch, better_read_more-823380+1300568-195.patch, failed testing.

pillarsdotnet’s picture

Status: Needs work » Needs review
FileSize
13.78 KB

And again.

Lars Toomre’s picture

@pillarsdotnet - You are missing a blank line before @return in the docblock for field_has_read_more().

pillarsdotnet’s picture

@#198 by Lars Toomre on October 7, 2011 at 6:21am:

@pillarsdotnet - You are missing a blank line before @return in the docblock for field_has_read_more().

Thanks; corrected in both patches and re-rolled.

pillarsdotnet’s picture

Issue summary: View changes

Added link to blocking issue.

pillarsdotnet’s picture

Issue summary: View changes

Update links and remaining tasks.

pillarsdotnet’s picture

Status: Needs review » Postponed
Issue tags: -summary

Okay, now that both approaches pass tests, this issue is officially postponed until we get a response from catch, Frando, ysched, or bjaspan.

Re-opened and marked as blocking this issue:

pillarsdotnet’s picture

Issue summary: View changes

Correct the order of blockers; we've been waiting for a review a lot longer than we've been waiting on tests.

Alan D.’s picture

A quick search gave no clean results for a nice integrated method of handling teaser / body / readmore. There are about 5 or 6 related issues, but this appears to be the most active related thread. I am about to tackle this using multiple fields, but would love it if I didn't have to.

Requirements / Outline

A WYSIWYG on both Teaser / Body with different filter format options.
Teaser generated by:
a) Teaser field only
b) Trimmed body field
Read more shown if (default)
a) Both fields are present AND teaser != body

Planned fields

field_summary - text_long
field_include_teaser - list_boolean
field_body - text_long
field_readmore - list_integer << Set default override in Content type settings

Final UI

Summary
[ Textarea ]
[*] Include summary on full page view
Body
[ Textarea]
Read more
(*) Use summary and body fields to determine if a read more is required
( ) Always show a read more link
( ) Never show a read more link

Implementation

From this approach in D6, I would only really only would need to add a toggle in the node view hooks and a new conditional teaser_or_body view field.

In D7, then there is also:
a) Requires a way to upgrade from the existing body field or a way to convert this to text_long
b) A way to stop adding the default body field and replace with this field collection

Thoughts? Similar existing modules? I really need a solution in the next few days, so I will be starting this today. I've started a forum thread http://drupal.org/node/1318254 to continue this discussion and to stop polluting this thread with additional noise.

pillarsdotnet’s picture

Status: Postponed » Closed (won't fix)

Well, two weeks have passed with no input from any of the core field/entity maintainers, so I'm afraid this is a "Won't fix".

Please re-open this issue if you are a core field/entity maintainer and are willing to review one or both of the patches in #199.

joachim’s picture

Status: Closed (won't fix) » Active

Sorry, but that's ridiculous. Plenty more time passes with bugs in this sort of state without input from maintainers, and maintainers simply won't see a bug set to won'tfix, because if you're a maintainer you probably don't bother reading those.

geerlingguy’s picture

@pillarsdotnet - I have also waited for months for any attention for some patches I've worked on or would like to go in... If you're really disgusted with how things are going, rather than mark an issue as closed (especially since many others would still like the issue resolved), just unfollow the issue and forget about it. Your patch will likely be further tested at some point, and I'm pretty sure your username will be associated with the commit if it ever comes to happen.

Please stop marking these large issues as "won't fix" simply because they've been stalled.

marcingy’s picture

Status: Active » Needs review

Shouldn't this be needs review

catch’s picture

Yes, please don't won't fix issues just because they're stalled. I have issues that have been at CNR for months or years (and I've also been on holiday for most of the past three weeks). There's also no impasse here that needs feedback from a maintainer, the latest patch has barely been reviewed by anyone at all.

So I only see three options here:

1. Leave 'read more' on every teaser, mark this won't fix.

2. Just remove 'read more' support or make it optional or something.

3. Something like #99.

I'm not sure which is preferable but since this is an unintended regression from D6 we should try to do #3 probably.

If we go with #3 then #99 looks like it's along the right lines. However I'm not sure about whether this should be an entity level construct (i.e. $content['#readmore'] that Field API could then set but we allow other code to see it too), or a field API construct as set in the patch.

Jamie Holly’s picture

@Catch -

I believe #2 really shouldn't even be considered an option. I could imagine a site upgrading to D8 and suddenly having full nodes appear on multi-node pages. The only way I see that working is if a core-optional module is provided to provide 'read more' that is enabled by default.

#1 might not be bad, but if that were the case I believe that the trimming functions should actually be moved into a hook so that other modules could implement their own 'read more' or remove the core function all together. Possible something along the lines of hook_textfield_trim or something like that. (Technically you can override this now, but that requires overriding the formatter through hook_field_formatter_info_alter(). One problem I see there is that the module overriding it has to then make sure to handle/call the _text_sanitize and if this is overlooked we have a very serious security issue.)

I heavily favor #3, especially given the attention this issue has and going from the complaints I have heard about it. Placing of the construct is an interesting question though. 'Read more' is tied so closely to the entity level and field API system. I lean more towards this being constructed on the entity level though, since the functionality actually depends upon the presence of a display mode that utilizes the teaser function and the entity has to handle the site structure to display the different modes.

But I would say that in 99% of the cases out there, 'read more' is used solely by the node module. I can also see that changing as people start getting more comfortable with entity API and field API. An example would be a forum module that doesn't rely upon nodes/comments, but rather their own tables (this came to mind because of something I might be doing for a client). Given that I heavily lean towards keeping this in the field API system and letting the entities act upon a flag set by the the formatter.

Here's another use case I can think of if we go the #3 in field API route:

A publisher creates a special entity for the books they sell. In it they allow visitors to read a selected chapter and the introduction:
- A text field for the introduction that can be trimmed.
- A text field for the sample chapter that can be trimmed.

Now the entity in the teaser display can look the the #read_more flag and append a "continue reading" or whatever link to the bottom of that field, both of which would go to separate urls (/book/####/introduction, /book/####/sample).

I really believe keeping it in field API and making it something that can be easily implemented and modified while not giving false positives could lead to some really interesting things done down the road.

xjm’s picture

Issue summary: View changes

Update links.

xjm’s picture

Issue summary: View changes

Updated issue summary.

xjm’s picture

I closed #1300568: Fix tests that wrongly assume all teasers have a Read more link as a duplicate. Reasoning: D7/8 core currently has the assumption that a teaser always implies a "Read more" link. If we are changing that assumption in this issue, then we should also correct the tests that include that assumption in this issue, and add more sophisticated test coverage for the more sophisticated behavior (which the existing patch already does.

Attached:

  • Adjusts patch for the core/ directory move.
  • Updates existing tests to remove implicit assumptions from other tests (so the issue is no longer blocked by any other)
    • The assertions in the comment link tests are out of scope for the comment link tests anyway. Whether or not the comment count is shown is unrelated to whether the "Read more" link is shown.
    • The assertions in the node access test are changed to instead check that the node title links to the node. (The intent in that test is to confirm that nodes are linked or not based on access control, and the title serves this purpose just as well as the "Read more" link.)
  • Clarifies API documentation for the added API functions and test methods.
  • Adds various other code style cleanups.

It does not address @catch's comment above:

However I'm not sure about whether this should be an entity level construct (i.e. $content['#readmore'] that Field API could then set but we allow other code to see it too), or a field API construct as set in the patch.

xjm’s picture

Issue summary: View changes

Updated issue summary.

Tor Arne Thune’s picture

Status: Needs review » Needs work
+++ b/core/modules/node/node.testundefined
@@ -1100,8 +1100,8 @@ class NodeAccessBaseTableTestCase extends DrupalWebTestCase {
-      foreach ($this->xpath("//a[text()='Read more']") as $link) {
-        $this->assertTrue(preg_match('|node/(\d+)$|', (string) $link['href'], $matches), 'Read more points to a node');

There should probably also be a test to check if the read more link actually points to a node (or even better, points to the correct node; the one created in the test), as this check is removed by the patch.

xjm’s picture

Well, the removed test coverage wasn't intended test coverage (and has nothing to do with read more links; rather, it's a node access question), but we can add an additional assertion to the new tests.

chx also pointed out that (e.g.) $readmore should be $read_more.

Waiting for the bot to post any reroll.

Tor Arne Thune’s picture

But by removing it we lose the unintended test this gave us. I agree it should be removed, but it would be great to have a test to check if the read more link actually works (points to the correct node).
Maybe by using clickLink and assertText for the node title?

xjm’s picture

Right, but not in the node access tests. :)

Tor Arne Thune’s picture

Definitely not. The new tests added by this issue would allow this to be tested easily by adding clickLink and assertText on the title (or some more clever way).

xjm’s picture

Interesting. So it looks like the comment count display is dependent on the presence of the read more link. It shouldn't be. So we'll need a solution that decouples that as well.

xjm’s picture

Actually, come to think of it, there's a case to be made that the "Read more" link should be present when there are comments. Because, even if not in the node body itself, there's more to read in the comments. Can anyone confirm what the D6 behavior is for a node where the teaser is equal to the body, but there are comments?

Jamie Holly’s picture

In D6 comments don't matter. The read more link is totally dependent upon the node/teaser. Having it dependent upon comments should really be something for contrib to handle. The case being is that not everyone uses Drupal comments. Some may use 3rd party systems such as Disqus. In that case it would be up to that module to decide if read more should show for comments and connect with the Disqus API to determine if comments are present or allowed on that node.

xjm’s picture

Thanks Jamie! To clarify, the read more link:

  • Should always be present on a node when the summary is not the same as the body. (Provided by node.module, I think.)
  • Should potentially be present on a node when the summary is the same as the teaser, but there is other information to view. (Provided by the module that provides the other information. In the case of comments, comment.module would provide this, so it would not occur if comment were disabled.)

But if the second bullet doesn't happen in D6, then we probably need to fix comment.module now for the failures above.

This also raises the larger question of what the link actually means. For example, what if certain fields are displayed on the full node, but not the teaser? Should those count? The thing that bothers me the most about the patch above is special-casing longtext with summary fields. Really it's a node.module functionality and I don't think code for it should appear in the Field API at all...

joachim’s picture

+++ b/core/modules/node/node.module
@@ -1416,7 +1416,9 @@ function node_build_content($node, $view_mode = 'full', $langcode = NULL) {
-  if ($view_mode == 'teaser') {
+  // Only show the "Read more" link if the view_mode is 'teaser' and at least
+  // one field has the '#read_more' property set to TRUE.
+  if ($view_mode == 'teaser' && field_has_read_more($node->content)) {

So if we want something more generic, how about:

- move calling of field_has_read_more() to field module's implementation of hook_node_view().
- other modules such as comment can then opt to set the read_mode flag on a node in teaser view in their own hook_node_view() implementation.

Jamie Holly’s picture

That's what I meant was in the case of showing the read more link if node == summary and comments are there should be handled by the module that handles the comments (core, disqus, intense debate, etc.).

In the case of multiple text with summary fields, this does pose an interesting situation. Perhaps something along the lines of each field that has a true summary (summary != body) a flag is set on that individual field. The node module then checks each text with summary field and if one of those fields has that flag set then the read more link is displayed (same as D6).

This route would open up the possibility of a contrib module to do more advanced read more functionality. For example I have a node with 2 text + summary fields. Field 1 has an actual summary, but field 2 does not. A read more link could be appended to field 1's output and the link actually anchored to that field on the node view or even pull in the rest of the field via AJAX.

What this does is brings us more inline with the D6 functionality that everyone seems to want back, but opens us up for far more advanced features that work well with D7's field system.

xjm’s picture

Awesome, thanks @joachim and @Jamie Holly. That sounds like a much better direction for me as well. I'd go so far as to move the functionality out of the field module entirely, if possible.

Tor Arne Thune’s picture

Anyway, this is what I meant for checking the destination of the read more link.

joachim’s picture

Status: Needs work » Needs review
FileSize
11.55 KB

Here's the above patch with all the 'readmore' changed to 'read_more' and a typo fixed too.

Also, related bug which we really shouldn't take on here, this issue being complicated enough:

 * - $readmore: Flags true if the teaser content of the node cannot hold the
 *   main body content.

This line in core's node.tpl.php files appears to be a lie.

joachim’s picture

> - move calling of field_has_read_more() to field module's implementation of hook_node_view().

Ugh I'm talking rubbish there.

The 'read more' link is built *before* hook_node_view() is invoked. If we move it to be done after, we potentially break hook_node_view() implementations for other modules, hence it's an API change.

joachim’s picture

Modules like comment could set $node->read_more in hook_entity_prepare_view() perhaps?
But that's too early for fields. I think we need to stick to the same approach as in text_field_formatter_view, but maybe let that function set $node->read_more itself.

Then node_build_content() just has to check whether $node->read_more is TRUE to decide whether to show the link.

joachim’s picture

Here's a proof of concept of the idea from #227. Needs comments & docblocks etc.

It shows:

- text module setting $node->read_more directly
- comment module setting it if the node has comments. Perhaps not something to be included in this patch, but demonstrates it's possible.

Jamie Holly’s picture

For anyone looking at this problem, here is a simple hook I've done on a few D7 sites that makes the readmore function more like the D6 days:

function readmore_fix_node_view($node, $view_mode, $langcode) {
  if (!empty($node->content['links']['node']['#links']['node-readmore'])) {
    $keep_readmore = FALSE;
    // Loop through the bundle's displayed fields and look for a field that
    // has the text_summary_or_trimmed formatter.
    foreach (element_children($node->content) as $field) {
      if (isset($node->content[$field]['#formatter']) && $node->content[$field]['#formatter'] == 'text_summary_or_trimmed') {

        // Loop through all the items incase this node type allows multiple value bodies.
        // If summary is set and doesn't equal value then we will keep the read more.
        foreach ($node->content[$field]['#items'] as $item) {
          if ($item['summary'] && $item['summary'] != $item['value']) {
            $keep_readmore = TRUE;
          }
        }
      }
    }
    
    if (!$keep_readmore) {
      // Drop the read more link
      unset($node->content['links']['node']['#links']['node-readmore']);
    }
  }
}

Not the best thing, but it's worked out great for me and beats having to patch core.

Status: Needs review » Needs work

The last submitted patch, 823380.228.drupal.node-read-more.concept.patch, failed testing.

hass’s picture

Could someone be so kind to point me to a working workaround for D7 until a final solution has been implemented. 230 comments are really heavy to follow and this case is still tagged with D8 what is no good sign...

John_B’s picture

Issue summary: View changes

Updated issue summary.

John_B’s picture

You don't need to read them all! Skimming through the above thread points to the 'Better Read More' sandbox and project application nodes.

[EDIT: See post below. I was wrong. Better Read More is another project I have also used, and I get their names confused.]

Alan D.’s picture

I've updated the issue summary to provide a link to the Read More Control module, (monochromes old sandbox project).

xjm’s picture

To address this issue, someone needs to fix the patch in #228, which is apparently causing a regression.

tim.plunkett’s picture

Status: Needs work » Needs review
FileSize
11.35 KB

Rerolled. This should fix the exceptions, not sure about the failure.

Status: Needs review » Needs work

The last submitted patch, drupal-823380-235.patch, failed testing.

tim.plunkett’s picture

Status: Needs work » Needs review
FileSize
11.42 KB
6.91 KB

Similar to NodeAccessBaseTableTestCase, this new class relies on taxonomy terms, so it needs the standard install profile.

tim.plunkett’s picture

FileSize
11.67 KB

The above patch only fixed some of the failures, this one should do it.

The interdiff for this patch from #237 is:

     $count = $this->xpath('//div[@id=:id]/div[@class=:class]/ul/li', array(':id' => 'node-' . $this->node->nid, ':class' => 'link-wrapper'));
-    $this->assertTrue(count($count) == 1, t('One child found'));
+    $this->assertTrue(count($count) == 0, 'The read more link is not shown when there are no comments.');

The failure was enforcing the wrong behavior.

yurtboy’s picture

FileSize
12.26 KB

Git reports errors when applying the patch

Checking patch core/modules/comment/comment.module...
Checking patch core/modules/comment/comment.test...
error: core/modules/comment/comment.test: No such file or directory
Checking patch core/modules/field/modules/text/text.module...
Checking patch core/modules/node/node.module...
Checking patch core/modules/node/node.test...
error: core/modules/node/node.test: No such file or directory
Checking patch core/modules/poll/poll.module...

I changed some of the paths in your patch and then made a second patch to deal with a change that was in a different file all together. (seems two diffs where in one file that now had to be applied to two different files, not sure on that one.)

This is my first official patch submit following drupalladder, so sorry if I got it wrong.

Status: Needs review » Needs work

The last submitted patch, drupal-823380-239.patch, failed testing.

yurtboy’s picture

so much for that. Will review the test results and see if I can do a better patch.

tim.plunkett’s picture

Status: Needs work » Needs review
FileSize
12.19 KB

#1592966: Convert node tests to PSR-0 and #1588284: Convert comment tests to PSR-0 moved all the tests around on Tuesday.
Each class gets its own file now, so splitting NodeTeaserReadMoreTest into its own file.

Note for backport, #239 will be the easiest way to go.

yurtboy’s picture

Patch applied cleanly.
Attached is a screenshot of quick test of Long and Short nodes on the home page.
I can do mores tests as needed for d8.
Can do d7 as well.

bleen’s picture

Status: Needs review » Needs work
+++ b/core/modules/comment/comment.moduleundefined
@@ -627,6 +627,19 @@ function theme_comment_block() {
+function comment_entity_prepare_view($entities, $type) {
+  if ($type == 'node') {
+    foreach ($entities as $node) {
+      if (!empty($node->comment_count)) {
+        $node->read_more = TRUE;
+      }
+    }
+  }

Given that we are adding this function, shouldn't we have a test that ensures the read more link appears when a node has a comment even if the trimmed version is the same as the full version?

Jamie Holly’s picture

I've never seen a CMS that considers comments as part of content when it comes to read more. This would probably be better left to contrib, especially since it's a lot easier to do:

if ($node->comment_count){
  $node->read_more = TRUE;
}

than it is

if ($node->comment_count == 0 && some_crazy_logic_to_check_if_teaser_same_as_body($node)){
  $node->read_more = FALSE;
} 

Edit:

Adding to that, we already have a some what "read more" when comments are present in the form of the comment link on the teaser view (1+ comment - you can click and read them. 0 comments - nothing more to see here).

swentel’s picture

Why don't we make an extra field from this and let actually people configure this on Field UI. The check now only works for text_summaries. That's making the assumption teasers only contain text and the full node as well. What if there's an image on there, but not on the teaser, then image_formatter_view should be patched as well .. basically any formatter in core .. and then every contrib out there should do this as well. This is a thing of the past imo.

If anyone's interested, I can come up with a 'extra field' approach which sounds much more saner imo.

- edit - reformatted a little.

bleen’s picture

I think swentel's approach in #247 sounds pretty reasonable... +1

Alan D.’s picture

@swentel
This could be a biggish change, you can help co-maintain Read More Control if you want to establish a contrib version before trying to get something like this into core. This allows configuration on a global, content type and instance settings, but the first two would need to be defaulted to sane defaults (if field is long text then test for differences for example) for core I would think.

Alan D.’s picture

I've just reformatted the Read More Control module to handle any view mode on any entity (with some restrictions) for any interested parties: With this fresh in my mind...

Regarding #243, if you have a multi-value text field, the if the first delta is different, and the second is the same, the delta '#read_more' attribute would take the $items read more flag, thus giving a false reading on the delta attribute. This does not appear to be used, so is this even needed? Maybe place this on the field itself.

+  $entity->read_more = $read_more;
+  $element['#read_more'] = $read_more;
+
   return $element;

Or if there is no reason for the field having this info (it is a node only property after all):

+  $entity->read_more = $read_more;
+
   return $element;

Also, there is the false assumption that the full view mode will show and render the entire long text field. This would probably still throw up false read mores on maybe 1 out of every 3 or 4 projects for us.

i.e. If you say had a location node that had a hidden long text field for rendering in a Google map info popup, then any teasers of these nodes would always result in a read more link.

And I do not know of a simple way around this other than trying to load the "full" view mode, and if found to do comparisons against this. In core, Taxonomy vocabulary doesn't have a full view mode and this is also the case in many contrib entities. This seems mighty wrong at the field level.

Since this is limited to node_build_content(), then this is probably a better place for this.

This is about as simple and efficient as I could get it in the Read More Control module using hook_entity_view() and roughly applied to node_build_content():

function node_build_content($node, $view_mode = 'full', $langcode = NULL) {
....
  if ($view_mode == 'teaser') {
    // Parse instances and test if any fields need to be generated to see if there is a read more required
    $entity->read_more = FALSE;
    $view_mode_settings = field_view_mode_settings('node', $node->type);
    $actual_full_mode = empty($view_mode_settings['full']['custom_settings']) ? 'default' : 'full';
    foreach (field_info_instances('node', $node->type) as $field_name => $instance) {
      // Get the field display info for full view mode.
      $display = field_get_display($instance, $view_mode, $node);
      $display_full = field_get_display($instance, $full_mode, $node);
      $field = field_info_field($field_name);
      // If the full view mode is hidden, we can ignore this field.
      if ($display_full['type'] == 'hidden') {
        continue;
      }
      if ($display['type'] == 'hidden') {
        $node->read_more = TRUE;
        break;
      }      
      $items = field_get_items('node', $node, $field_name, $langcode);
      if (empty($items)) {
        continue;
      }
      $func = "readmorecontrol_{$display['module']}_compare_items";
      if (function_exists($func)) {
        $content = array(
          'display' => $display,
          'display_full' => $display_full,
          'instance' => $instance,
          'field' => $field,
          'langcode' => $langcode,
        );
        if ($func($items, $content)) {
          $node->read_more = TRUE;
          break;
        }
      }
    }
    if ($node->read_more) {
      $node_title_stripped = strip_tags($node->title);
      $links['node-readmore'] = array(
        'title' => t('Read more<span class="element-invisible"> about @title</span>', array('@title' => $node_title_stripped)),
        'href' => 'node/' . $node->nid,
        'html' => TRUE,
        'attributes' => array('rel' => 'tag', 'title' => $node_title_stripped),
      );
    }
  }

And the only comparison callback that I implemented was for the text module:

/**
 * Implements the callback readmorecontrol_MODULE_compare_items().
 */
function readmorecontrol_text_compare_items($items, $content) {
  extract($content, EXTR_SKIP);

  // We can bypass processing of some combinations.
  if ($display['type'] == $display_full['type']) {
    switch ($display['type']) {
      case 'text_default':
      case 'text_plain':
        return FALSE;
    }
  }

  // Avoid additional processing, do this once for both if required.
  $needs_sanitization = $display['type'] != 'text_plain' || $display_full['type'] != 'text_plain';
  $has_summary = $display['type'] == 'text_summary_or_trimmed' || $display_full['type'] == 'text_summary_or_trimmed';

  foreach ($items as $delta => $item) {
    $sanitized_text = $needs_sanitization ? _text_sanitize($instance, $langcode, $item, 'value') : '';
    $sanitized_summary = $has_summary ? _text_sanitize($instance, $langcode, $item, 'summary') : '';
    $display_text = '';
    $full_display_text = '';
    foreach (array('display_text', 'full_display_text') as $var) {
      $test_display = $var == 'display_text' ? $display : $display_full;
      switch ($test_display['type']) {
        case 'text_default':
        case 'text_trimmed':
          $$var = $sanitized_text;
          if ($test_display['type'] == 'text_trimmed') {
            $$var = text_summary($$var, $instance['settings']['text_processing'] ? $item['format'] : NULL, $test_display['settings']['trim_length']);
          }
          break;

        case 'text_summary_or_trimmed':
          if (!empty($item['summary'])) {
            $$var = $sanitized_summary;
          }
          else {
            $$var = text_summary($sanitized_text, $instance['settings']['text_processing'] ? $item['format'] : NULL, $test_display['settings']['trim_length']);
          }
          break;

        case 'text_plain':
          $$var = strip_tags($item['value']);
          break;
      }
    }

    if ($display_text != $full_display_text) {
      return TRUE;
    }

  }
  return FALSE;
}

So this is a lot of additional cruft floating around, so I'm not sure if this is a good track to go down :(

yoroy’s picture

Assigned: Unassigned » swentel

Sooo, what about that 'make it a field' suggestion in #247?

Assigning to swentel so that he may provide some direction on how to implement this as a field :-)

Alan D.’s picture

IMHO, it would be best to calculate the existence of additional data as per tim's patch in #243 for all long text fields, and then parse the body field in node_build_content() to generate the read more flag. This brings back the default Drupal 6 behaviour and provides a platform for extending this in contrib.

swentel’s picture

Yoroy, you're lucky I like you because I basically gave up on this issue :) Attached is a patch that exposes a 'Read more' field on Field UI as an extra field which now allows you to choose per bundle and per view mode whether you want to print a read more link or not. Screenshot attached. Tests might probably fail as I haven't looked at them right now, just posting to see whether you like the approach or not.

Screen Shot 2012-11-09 at 19.14.15.png

As I've said in #247, relying on calculations on body fields is stupid (which doesn't mean I'm right though). I'm biased of course on Field UI, which basically sucks for displaying entities as we know right now and I've enhanced its behavior with Display suite exposing any property of your entity, or at least, the most common ones. I've more or less tried the same approach over at #1166114: Manage Displays Search Results doesn't manage the display of the search results, but the patch there at #65 made it smarter so no 'extra fields', just a smarter mechanism. We could do the same for a 'title' field, because, seriously, title field relying on $page, sigh, it makes me cry.

Anyway, this patch is easy and if contrib still wants to override the behavior, they can do so altering the #links array on the entity, just don't let core make crazy calculations because they won't work ever for every use case. Also, this is extremely easy to backport as well.

swentel’s picture

FileSize
2.45 KB

Oh seriously, here's the patch.

swentel’s picture

Status: Needs work » Needs review

And let's see what the bot says, sorry for the spamming.

swentel’s picture

FileSize
1.57 KB

Patch contained cruft from another one, sorry (again).

joachim’s picture

Status: Needs review » Needs work

> As I've said in #247, relying on calculations on body fields is stupid (which doesn't mean I'm right though).

Whether you're right or wrong, this approach doesn't fix the stated problem of this issue: that the 'read more' link shows on a teaser when there is nothing further for the user to read.

Exposing this as a field is a great new feature, definitely. But all it does for this issue is move the problem to being per-content type. You could still have particular nodes of a particular content type which exhibit the bug.

swentel’s picture

Assigned: swentel » Unassigned

Whether you're right or wrong, this approach doesn't fix the stated problem of this issue: that the 'read more' link shows on a teaser when there is nothing further for the user to read.

Sure, but core shouldn't fix this, D7 vs D6 has become more complicated because of Field API. anyway, unassigning and unfollowing, I don't care about this one anymore.

nils.destoop’s picture

Status: Needs work » Needs review

#257 if you want to be the read more be dependent of the body field. You should implement it in your custom module. The read more should never be dependent of the body. Your detail page can show way more then the body alone (videos, pictures, body text, related information, ...).
Marking this as needs review again. All the other use cases are custom.

The last submitted patch, 823380-256.patch, failed testing.

joachim’s picture

Status: Needs review » Needs work

> Sure, but core shouldn't fix this,

> #257 if you want to be the read more be dependent of the body field.

So what both of those are saying is that this is 'wontfix'.

But comments above show we have a lot of users who not happy about this regression in behaviour.

Anonymous’s picture

It's a bug. It's hard to fix. It may not be very important (but that's a matter of opinion).

"It's hard to fix, and not very important, therefore it is not a bug" makes no sense.

"It's not worth fixing" is a logically consistent thing to argue. But no one is forced to work on this who doesn't want to. So if you think it is not worth fixing, you can ignore it!

bleen’s picture

It only makes sense to fix this if you assume that the "more" in "read more" refers to the body field only. As was stated in #259:

The read more should never be dependent of the body. Your detail page can show way more then the body alone (videos, pictures, body text, related information, ...).

It isn't that this is hard to fix, it's that it cannot be fixed in a generic way that would work for core because different sites will have different (legitimate) definitions of what "more" means.

A "read more if body is trimmed" module would be easy enough to create for contrib.

I think Swentel's patch from #256 should be considered, but it doesnt really help this issue. My vote is "wont fix"

Alan D.’s picture

FileSize
13.15 KB

"because different sites will have different (legitimate) definitions of what "more" means"

I managed to define 5 "global" options, that work in 95% our use-cases:

Generic response why not to move to display settings.

I initially loved this concept, but after working on a site that has 60 content types and 4 commonly used display modes, each time you want to alter these, you have 240 admin screens to go through (thank god I can write update scripts for the field display settings). It is a domain access based site that has 8 current domains and it is possible to define domain specific view mode settings, so absolutely worst case is that to alter these would involve going through nearly 2000 display settings pages. Big -1

Also, additional fields are shown by default in Drupal 7 #1256368: Add 'visible' key to hook_field_extra_fields(), and afaik, there is no way to target individual display modes either.

Alan D.’s picture

Unrelated, but pinging as lots of generic interest in this thread. I am starting to extend the functionality of Read More Control module to be entity based, to support any view mode and to merge in the functionality of Read More Link module. Ping me if you are interested in helping.

yoroy’s picture

Status: Needs work » Closed (won't fix)

At 260+ comments in, Drupal 7 nearing it's second year out in the wild maybe it's better to non-fix this for D7 and look at a different approach for D8. I think having a better behavior for this than current D7 *is important*, but to me it seems we're getting hung up on fixing the bug as-is whereas a different approach all together seems to make more sense. Nor do I think 60 content types is an strong argument against doing that. I'm sure there are more changes you can make that force you to update 2000 display settings.

I opened #1837100: Provide a generic Read more field and won't fixing this one. Feel free to re-open if you want to fix it as-is in here though.

Summit’s picture

Status: Closed (won't fix) » Active

Hi,

Yes I want to get this fixed in D8 and then backported to D7 and D6 because it is a annoying thing to have and because there are so many D7 sites out there which have this problem (that's why this thread is such a big one I think!). So setting this to active again. And I like the approach of #253 on content type. The same sort of working as having comments etc..
I think to have more than 2000 changes will always need a smart database query/script instead of screen-entry so I (in my humble opinion) think that is not a reason why not to move forward on a solution based on #253

Greetings, Martijn

j. ayen green’s picture

In lieu of any other fix, how about an ugly fix where you can choose at the node level to disable read-more (override it), and an admin choice of whether the default for that option is on or off?

yoroy’s picture

Summit: the fix as described in #253 was moved to #1837100: Provide a generic Read more field, if you support that route, start following that issue, not this one. The issue is so long because with the fields system in d7 this particular way of determining wether to show a read-more link or not became very hard to solve.

hass’s picture

It looks like the read more control module has solved these hard "issues".

klonos’s picture

...+ there's only 68 people following this issue, so I guess the "a lot of sites facing this bug" thing might be an exaggeration too. Besides, the Read More Control module has a user base of only ~1500.

marcingy’s picture

Category: bug » task
Priority: Major » Normal

This is not even a bug in many ways this is a task at best and most certainly not major.

fuzzy76’s picture

How is showing the user a "read more"-link when there isn't any more to read not a bug?

jtbayly’s picture

Category: task » bug

This is a bug. Pure and simple. If the fix isn't to only conditionally show "Read more" when it makes sense, then the fix is to never show "Read more". It could be either removed, or the text could be changed to say something that makes sense, like "view content."

When a person is on a Drupal site, and they see a link that says "read more" (notice that word "more") does that not communicate something very particular? Yes it does. It communicates that they will be able to read umm... *more* if they click the link. This isn't making a site difficult for developers to work on. It's not even making it difficult for site content managers to use. It's making it difficult for the public to navigate the site without thinking they're going insane!

Oh, and the fact that this bug can be fixed in contrib has nothing to do with whether or not it is a bug or whether it should be fixed.

-Joseph

jtbayly’s picture

Issue summary: View changes

Updating the issue summary to point to contrib for an alternative solution.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

mpp’s picture

Issue summary: View changes
Status: Active » Closed (duplicate)

I agree that the "read more" link needs work the real bug is described in this issue: https://www.drupal.org/project/drupal/issues/2662898.

Have a look at Berdir's comment in #17:

it might also need to be configurable, because not everyone wants those links and now with the update, they might suddenly show up, likely breaking designs.

Closing this issue in favor of #2662898.