Problem/Motivation
The previous issue summary was really addressing an issue that arose from using the Bootstrap theme.
However, the issue is that the base field "created" is displayed on the user entity display in a non-standard manner as it is hard coded with the html
$build['member_for'] = [
'#type' => 'item',
'#markup' => '<h4 class="label">' . $this->t('Member for') . '</h4> ' . \Drupal::service('date.formatter')->formatTimeDiffSince($account->getCreatedTime()),
];
in the file core/modules/user/src/Hook/UserHooks.php.
#34 suggested removing the 'Member for' from display.
Steps to reproduce
Proposed resolution
The discussion in comments #47 & #48, which is to expose the user entity "created" field in a standard manner that can be overridden like any other entity field, is the basis for a solution to this issue.
The solution implemented in MR 16405 is based on those suggestions as follows:
createdis configurable on User entity display and set to hidden by defaultmember_foris deprecated, and rendering that will trigger a deprecation warning- For backwards compatibility, existing sites upgrading to D11.5 or D12 will continue to show the
member_forextra field (if already configured to do so), with thecreatedfield added as hidden. Admins on those sites can update the display to use thecreatedfield instead beforemember_foris removed in D13 - New installations on D11.5 or D12 will have both the
createdfield andmember_foras hidden - There is test coverage for the deprecation and the upgrade path
Draft change record: https://www.drupal.org/node/3611943
Remaining tasks
Review
For product manager feedback:
The "Member for" (member_for) extra field on the User profile page is an accessibility concern (hard-coded <h4>), has cache invalidation issues because the time interval cache metadata is not captured or bubbled, and the markup is not overridable via usual field templates.
The first step is to deprecate and eventually remove the "Member for" extra field. Beyond that, there are a few options:
Make thecreatedfield configurable on display, and set default configuration to have label "Member for" and to show the time interval using the TimestampFormatter which updates display using JS. This caches correctly, makes field templates available, and removes the<h4>, but introduces complexity to the user profile page (and our performance testing) which otherwise does not have JS- Make the
createdfield configurable on display and hidden by default. This means that the User profile page is essentially empty by default, but can be configured for each site Make thecreatedfield configurable on display and set default configuration to hav label "Member since" and show as a static dateMake viewing user profile pages configurable globally like media. This likely would be a separate issue or meta, because it has "far reaching implications on the login destination page, navigation links, user profile links (node/comment author) and also the new standard front page which is /user". Could also direct /user and user logins to the front page or /admin instead.
Commit
User interface changes
Before (Drupal 11.4)
Markup:
<div class="js-form-item form-item form-type-item js-form-type-item form-item- js-form-item- form-no-label">
<h4 class="label">Member for</h4> 27 seconds
</div>
Screenshots
Standard

Umami

After (Drupal 11.5/12)
Standard

Umami

Introduced terminology
API changes
Data model changes
Release notes snippet
Because the markup for the "Member for" field on user profile displays is cached incorrectly and can have accessibility issues, "Member for" has been deprecated and is scheduled for removal in Drupal 13. Site owners or themers should remove "Member for" from their user profile displays and make any necessary corresponding theme changes. The "Created" field has been made configurable on the display, and site owner or themers can configure the display and theme the "Created" field with field templates to display similar information.
| Comment | File | Size | Author |
|---|
Issue fork drupal-2638250
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
vladimirausComment #3
markhalliwellI don't think it should be the Bootstrap "label" (class) component at all.
It should probably be an actualOr possibly just<label>DOM element?<strong>?Comment #4
markhalliwellActually, this is a core issue. The problem is that user_user_view() is hard coding this "label" class instead of using a proper render array that allows themes like us to tap into it.
Core does have a "label" render element type, it uses the form_element_label theme hook. I'm not entirely sure if that would be appropriate, but it may be considering that it's already using the "item" element type (which is why it's being wrapped by form_element).
The class "label" is used by bootstrap to denote a label component, which is not what we want here. Even if we did, the point is that we couldn't modify it to add the secondary (necessary)
label-defaultclass to make it show up (as in the screenshots above).Comment #5
markhalliwellAt second glance (and considering that it's already using the "item" element type), I think just moving it to the #title property should fix the problem. Let me see if I can't roll a patch quickly.
Comment #6
markhalliwellComment #7
heykarthikwithu@markcarver
On user login, i am able to see the "Member for" label (label is not hidden)
Are their any other ways to reproduce the bug?
Comment #8
markhalliwell@heykarthikwithu, use the Bootstrap base theme. However, that isn't what this issue is about. The label not showing up (because it's white text on white background) is just a side affect of this markup being hardcoded.
Comment #10
hkirsman commentedOn my site the fields are in
<div class="field__label">Label here</div> so after applying the patch there's no formatting.Also what bugs me is that there's no option in the admin to set the label to above, inline or hidden.
Comment #12
mlncn commentedAgree with needing to make the "Member for" output easily overridable with a template, but this changes markup from what is currently output— and doesn't actually provide any template suggestions to make overriding easy.
Comment #15
adamps commentedRe-roll the last patch. There are still outstanding questions, but it definitely helps solve the problem "'Member for' is displayed differently from other user fields".
@mlncn
True , but I would say that's because the current output is wrong. Without this patch "Member for" is quite different from any other fields that you add using /admin/config/people/accounts/fields - it is h4 and no other field is. After this patch, they are almost identical - the only thing missing is a colon after "Member for".
Good point.
@hkirsman
That's a limitation of
hook_entity_extra_field_infowhich is what is being used here.Arguably a better solution would be to expose the 'created' base field directly, which is closer to what happens on a node. However I'm not sure how feasible it is to change this now - could be tricky to avoid back-compatibility problems for existing sites??
@markcarver
The class "label" seems to be used in several places by Drupal core. I agree it's unfortunate that the bootstrap framework uses the same class for a different reason and I have raised #2923978: Drupal labels disappear for that. However that seems to be a problem for one specific contrib theme, and it shouldn't stop us from using the label class if that is the right thing for Drupal core.
Comment #16
markhalliwellThis adds a theme hook suggestion so it can be targeted.
---
That being said, this "field" should really be converted into an actual field, not some arbitrary afterthought injected in an alter hook.
Comment #17
adamps commentedThanks @markcarver, that seems like the right fix here - it addresses the specific problems in the title, and is definitely a step in the right direction.
If anyone feels inclined they could raise a follow-on issue for "use an actual field".
Comment #18
xjmHm, not sure about this change. It does change the markup and the appearance, including the layout of the element so that it's now on two lines instead of a single line. It's also switching the field from a semantic element in HEAD (
<h4>) to<label>, which I don't think is supposed to be used for non-form elements.Tagging for accessibility review to double-check that.
Comment #19
adamps commented@xjm thanks for your review.
Do you think it would be better to fix this 'properly'? Now that we have #2392845: Add a trait to standardize handling of computed item lists maybe we could swap 'member_for' from
hook_entity_extra_field_infointobaseFieldDefinitionswithsetComputed(TRUE)? Then it definitely would be formatted exactly like all other fields. The core installation profiles could set'label' => 'inline'to make it on one line. It would be a more complex fix, not sure if anyone here would have time to do it.Comment #20
adamps commentedHere's an alternative approach switching to a computed field. It seems much cleaner and the output is identical to other fields of course. It also allows the site builder to customise the format.
The patch likely needs more work to fix tests and provide a hook_update. However I'd like to get some feedback on the general concept first.
Warning: with this patch you will see this issue #2686409: Time Ago summary does not render on Manage Display for Timestamp and Datetime fields
Comment #22
adamps commentedComment #23
markhalliwellIf this is the case, then I would imagine that all
itemrender elements (\Drupal\Core\Render\Element\Item) should be using a different#theme_wrapperthanform_element. Regardless, that would be out of scope for this issue and is really an entirely separate issue from this one.That being said, I really do prefer the computed field approach since it doesn't deal with a custom render array at all and allows an actual field to be rendered/targeted. Plus converting this into a "proper" field means that it doesn't use
<label>and users can choose where said label is displayed, so "win-win-win".---
The only setting that needs to be here is
past_format. The rest can be removed since they are the same as\Drupal\Core\Field\Plugin\Field\FieldFormatter\TimestampAgoFormatter::defaultSettings.I think the weight should be the same as the original: 5.
Comment #24
adamps commentedComments done thanks.
I would be very grateful if someone can explain why my patches for the new file are failing to apply. I ran git diff as normal. The error output is
error: dev/null: No such file or directoryComment #26
adamps commentedNever mind it seems to have applied this time.
Comment #27
idebr commentedClosed #2698019: user "member for x time" is hardcoded as a duplicate issue.
Comment #28
markhalliwellThe failing tests in #24 is because this new (proper)
member_forfield needs to be added to the expected output.We should also probably add a test to ensure that this computed field outputs as expected? At the very least so we don't delete it or change it to a manual render array again. Idk.
Comment #29
adamps commented@markcarver Thanks for the analysis. I am not familiar with JSON, so please bear with me asking a basic question. Would live sites also see the extra field appearing in JSON output? Is this definitely desirable? - or is it potentially a back-compatibility problem?
Comment #30
markhalliwellYes and probably, yes.
No, because this is adding a new field. It would only be a BC problem if existing sites relied on a field that was suddenly taken away.
Comment #31
adamps commentedThanks for explaining. I'm out of time for now, so if anyone else wants to fix the tests please go ahead.
Comment #34
geerlingguy commentedJust ran into this for the nth time, and noting that the whole feature seems a bit strange to me; besides a certain subset of site types, the value of having "member for" as a displayed-by-default field on the user profile doesn't seem desirable. I've used CSS to hide it way too many times... but maybe for Drupal 9 we can just drop it, and if someone wants to replicate the functionality, they can either add it via theming, or by a computed field or something?
Comment #35
geerlingguy commentedAttaching re-roll against 8.7.x (no diff, patch from #24 re-applied cleanly) for the testbot to take another stab.
And I think we would definitely need to add a test for this field (to prevent regressions), and either:
In either case, this would be a frontend change which could cause site owners to get a little upset (their theming of the user profile would most likely be affected, especially if they hid the 'Member for' output before, and it popped back in as a new field), so it would need a change record and be in a new minor release (at least).
Comment #37
geerlingguy commentedWhen I visit the 'Manage display' page for user accounts, I get the following errors with the above patch:
Comment #40
Christopher Riley commentedHas this issue ever been resolved? It seems trivial I know but this has been goobered long enough and should be a simple fix.
Comment #43
djg_tram commentedOnly five years and still the same bug. :-))
Comment #46
larowlanI agree the computed field is the best approach
Comment #47
berdirNot convinced, an extra field definition has non-trivial overhead, seems quite complicated. The _only_ thing the computed field now does is display created with a different label. Otherwise it's just duplicating the created field.
We could experiment with just rendering the created field with the timestamp_ago formatter which we've had since 2014 for the extra field.
A feature to override the label for display would be useful, because then we could possibly just drop this entirely and if you want it you could show the created field with that label (or any other). There are many use cases for that.
Comment #48
larowlanThat sounds much better
You should be able to use a base field override to change the label, so in theory that could go in the standard profile because this feature doesn't belong anywhere but there in my book
Comment #50
mohit_aghera commented- Updating the initial patch with the approach discussed in #47 and #48
- I haven't included the interdiff as it is completely different approach compared to previous patches.
- Doing one test bot run manually to see possible failures.
Comment #51
medha kumariReroll the patch #16 with Drupal 9.5.x
Comment #52
medha kumariReroll the patch #16 with Drupal 9.5.x
Comment #53
medha kumariReroll the patch #16 with Drupal 9.2.x
Comment #54
medha kumariReroll the patch #16 with Drupal 9.2.x
Comment #55
prasanth_kp commentedPatch #52 failed to apply on Drupal 9.2.x-dev.
Comment #56
mohit_aghera commentedI think based on feedback on #47and #48, the implementation approach in #50seems correct.
I am hiding other patches from #51 to #54
Comment #57
mohit_aghera commentedComment #58
mohit_aghera commented- Fixing multiple test cases and adding a configuration files on user module's config/install folder.
- Uploading and triggering test bot to see if adding file in module's config/install folder causes more failures.
- There are still a couple of test cases related cache are failing. Debugging those.
Keeping it assigned to me
Comment #59
smustgrave commentedThis issue is being reviewed by the kind folks in Slack, #need-reveiw-queue. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge require as a guide.
Tagging for an issue summary update as the current one is outdated and there is no proposed solution that matches the patch. Should happen probably first so the agreed upon solution is seen by everyone
Testing on an Umani install for 10.1.x and the label "Member for" appears
But the feature of being able to change the label as proposed in #47 I don't see.
At this time we will need a 10.1.x patch as #58 does not apply to 10.1.x
Please do not just reroll before understanding the agreed upon solution in the IS.
Comment #61
kksandr commentedReroll the patch #57 with Drupal 11.x
Comment #63
jayelless commentedAssign as DrupalSouth 2026 cotribution day task.
Comment #64
jayelless commentedReplace the 'member_for' extra field with the standard 'created' field for display of user entities.
Comment #66
jayelless commentedComment #67
smustgrave commentedSummary still needs to be updated. Not seeing the decision for dropping the member_for field, will definitely need a change record as I'm sure that's being used in contrib/custom modules.
Thanks!
Comment #68
kentr commentedIt looks like the decision to drop the
member_forfield was in patch #51, in response to #47 & #48.The MR appears to build on patch #51.
Though I'm not saying that the changes accomplish what #47 & #48 propose, or do it in the best way. I can't tell.
Comment #69
kentr commentedThis has an accessibility component due to the
h4: #3533586: "Member for" needs a div tag instead of h4 to pass accessibility check.Also, it's better to not assign ownership in most cases: Assigning ownership of issues
Comment #70
quietone commentedComment #71
quietone commentedAdded before and after images.
The tests are failing due to a caching issue, something I know little about.
Comment #72
godotislateThe cache issues are that the TimestampAgo formatter captures the cacheability from
DateFormatter::formatDiff(), and that has max-age 0 because the display is meant to change based on the time elapsed. The existing "Member for" actually has a cache invalidation bug because the hook does not capture or bubble the cache metadata, so the value does not change as expected.Instead of that formatter, the Timestamp formatter with the time_diff setting should be used (introduced in #2921810: Allow TimestampFormatter to show as a fully cacheable time difference with JS), because that uses JS to update the time interval display.
I'll see if I can take a crack at this unless someone else gets to it first.
Comment #74
godotislateStarting working on using the TimestampFormatter with the
time_diffsetting, so that caching works as expected and JS is used to update the display. Originally I went with the base field override idea added to only the standard and Umami profiles, per #48, but I ran into a few test failures because of expectations of the "Member for" label even outside those profiles. There was also complications creating base field override translated config for "Member for" label for Umami in Spanish.I switched to the changing the created field label in the base field definition, similar to the approach @jayelless took in MR 15740. There are a couple more test failures I have to work through, as well as an update path test, hence why the MR is still in draft, but I'm hoping to get back to it either this weekend or sometime soon. After I have that MR ready, I'll also work on an MR against 11.x, because I have some ideas on how to do deprecation.
Comment #78
godotislateOK, I changed my mind a little since #74. Since 11.5 and Drupal 12 release at the same time, I decided to deprecate the
member_forextra field for Drupal 13 instead to give more time. As a result, there's only one MR needed, and I closed MR 16342 and opened MR 16362 instead, because the post_update hook looks different.Summary of approach:
createdis configurable on User entity displaycreateddefault label now is "Member for" instead of "Created"createddefault display is configured with the TimestampFormatter using the interval (time_diff) settingsmember_foris deprecated, and rendering that will trigger a deprecation warningmember_forextra field (if already configured to do so), with thecreatedfield added as hidden. Admins on those sites can update the display to use thecreatedfield instead beforemember_foris removed in D13createdfield andmember_foris hiddenIt was a bit of a challenge updating the performance tests with the time-diff JS added to the user profile page. Thanks to @berdir and @catch for their assistance on Slack. Though since that took more time than expected, there are IS updates and screenshots of Standard and Umami before and after that I will have to do later.
In the meantime, the MR and CR are ready for review.
Comment #79
godotislateUpdated IS and provided screenshots.
Comment #80
godotislateComment #81
godotislate@berdir brought up good suggestions in MR comments, which I think should get product manager review, so tagging here as well as presenting the options in this comment and IS:
For product manager feedback:
The "Member for" (
member_for) extra field on the User profile page is an accessibility concern (hard-coded<h4>), has cache invalidation issues because the time interval cache metadata is not captured or bubbled, and the markup is not overridable via usual field templates.The first step is to deprecate and eventually remove the "Member for" extra field. Beyond that, there are a few options:
createdfield configurable on display, and set default configuration to have label "Member for" and to show the time interval using the TimestampFormatter which updates display using JS. This caches correctly, makes field templates available, and removes the<h4>, but introduces complexity to the user profile page (and our performance testing) which otherwise does not have JScreatedfield configurable on display and hidden by default. This means that the User profile page is essentially empty by default, but can be configured for each sitecreatedfield configurable on display and set default configuration to hav label "Member since" and show as a static dateComment #84
godotislateOn Slack, @gábor hojtsy was OK with this approach, so did this in MR 16405.
"Member for" still deprecated in Drupal 11.5, to be removed in Drupal 13
Created field is now configurable in user display, but hidden by default on existing and new installations.
Comment #85
godotislateComment #86
godotislateComment #87
berdirLooks great to me, happy to get rid of the member of by default. Just one comment on the upgrade path test.
Also created #3613118: Allow to disable user profile pages
Comment #88
godotislateI think I got all the MR feedback.
Comment #89
berdirThanks, looks good to me now.
Comment #90
larowlanJust one suggestion on the MR
Comment #91
godotislateReplied to MR comment with an alternate suggestion.
Comment #92
godotislateOpened #3615904: Display a warning in UI to notify users to remove "Member for" extra field from user display to look into ways to notify admins about the deprecation in the UI. I think this addresses the MR comment, so setting this back to RTBC.
Comment #93
larowlanThanks for that. Couple of questions on MR
Comment #94
godotislateMade changes per latest MR comments. Setting to RTBC because I think the change is straightforward, but please set back to NR if more appropriate.
Comment #95
quietone commentedI found a few things that need attention. I have made suggestions in the MR for those. But there is one question about a comment that isn't clear to me. So, setting back to needs work for that.
I reviewed the change record and made some tweaks. The way I read it the part about what sites upgrading sends 2 messages. One is that nothing needs to be done because existing theming works and the other is that they need to manually update. Maybe I am having an off day so keep that in mind.
Comment #96
godotislateThe intended message is that sites upgrading from < 11.5 can go to 11.5 or 12.0 without changing anything right away. The configuration of the "Member for" extra field will not be changed in the update, so their existing theming and templates will continue to work.
They will need to update relevant configuration and theming for Drupal 13, when the extra field will be removed altogether.
If that is not clear in the CR, I welcome any suggestions.
Comment #97
godotislateThank you for the review, @quietone! I applied suggestions and made edits that I hope provide more clarity.
Comment #98
quietone commented@godotislate, yes much easier to follow. Thanks
Comment #99
godotislate@quietone Is there anything else that needs attention, or can this go back to RTBC?
Comment #100
quietone commentedSorry! Yes, back to RTBC
Comment #101
godotislateAdded a release note snippet as well.
Comment #102
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #103
godotislateRe-based for merge conflict in post update hook after #256287: Give roles a description value was reverted.
Comment #105
larowlanCommitted 92812ef and pushed to main. Thanks!
Moving to 11.x for backport. Doesn't apply cleanly, conflict is on
Comment #106
larowlanHeld off publishing the change record until this is in 11.x
Comment #108
godotislate11.x MR ready: https://git.drupalcode.org/project/drupal/-/merge_requests/17007
Comment #109
godotislateI'm going to self-RTBC the backport, because the only merge conflict was in FieldBlockDeriverTest. In 11.x, the test was using the deprecated "Layout Builder Expose All Field Blocks", but the test now configures the user display explicitly for the assertions, so it's not needed.
Comment #110
longwaveCommitted and pushed 429cf5057f1 to 11.x. Thanks!
Comment #113
longwavePublished the change record.
Comment #114
longwave