Problem/Motivation
Monolingual site just installed, enable experimental admin_theme, go to /admin/people, a warning is issued:
Deprecated function: Using null as an array offset is deprecated, use an empty string instead in Drupal\Core\Entity\ContentEntityBase->hasTranslation() (line 984 of core/lib/Drupal/Core/Entity/ContentEntityBase.php).
Steps to reproduce
- Install Standard profile from
mainin English - Log in.
- Enable the experimental
admin_theme. - Set it as your administration theme.
- Go to
/admin/people
You're welcomed with Deprecated function: Using null as an array offset is deprecated, use an empty string instead in Drupal\Core\Entity\ContentEntityBase->hasTranslation() (line 984 of core/lib/Drupal/Core/Entity/ContentEntityBase.php).
No language aside of English is present in the system, but
core/themes/admin/templates/views/views-view-field--status.html.twig uses:
{% set entity = row._entity %}
{% if entity.hasTranslation(row.node_field_data_langcode) %}
{% set entity = row._entity.getTranslation(row.node_field_data_langcode) %}
{% endif %}
which ends up being hasTranslation(langcode: NULL)
Proposed resolution
I'm not against hardening getTranslation(), but the actual problem is that the presentation layer shouldn't mangle with entity translations. row._entity will already have the entity in the negotiated language. And if that's not the case, is not a twig template who should fix that.
So: we should just delete
{% if entity.hasTranslation(row.node_field_data_langcode) %}
{% set entity = row._entity.getTranslation(row.node_field_data_langcode) %}
{% endif %}
from core/themes/admin/templates/views/views-view-field--status.html.twig.
Verified this is the only template doing something like that.
Remaining tasks
- MR.
- Does this need tests? I don't think so.
User interface changes
Ideally none. No warnings are issued.
Introduced terminology
N/A
API changes
N/A
Data model changes
N/A
Release notes snippet
N/A
AI disclosure
None. Zero. Nada.
| Comment | File | Size | Author |
|---|---|---|---|
| #41 | Screenshot 2026-08-19 at 9.01.07 AM.png | 88.97 KB | godotislate |
| #41 | Screenshot 2026-08-19 at 12.00.39 PM.png | 87.33 KB | godotislate |
Issue fork drupal-3580733
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
penyaskitoVerified this is the only template doing something like that.
Comment #3
penyaskitoComment #5
penyaskitoComment #6
penyaskitoComment #7
smustgrave commentedSeems this came over from the gin move over to core? Either way the error does go away with the change.
Comment #8
penyaskitoComment #9
alexpottThis was added to fix a bug - see #3502789: The "Unpublished" badge for an unpublished translation is green - yes it is causing problems elsewhere and perhaps is not the correct fix but we should cause this.
Comment #10
alexpottSee also #3576477: Langcode not correctly detected in field--status which leads to PHP8.5 deprecation issue which is the same issue just for gin.
Comment #11
alexpottI think we need a different solution to the original problem in #3502789: The "Unpublished" badge for an unpublished translation is green
Comment #12
berdirMy suggestion would be that the theme shouldn't work what is apparently bug/inconsistency between views/entity translations. The whole template seems a bit problematic. It comes with a hardcoded assumption that the published status field is called "status" and that the entity for it does have an isPublished() method.
I'd suggest creating a new bug report in core about that, investigate what exactly is going on and work on a better resolution of this?
Comment #13
alexpott@berdir I agree - I think we should remove core/themes/default_admin/templates/views/views-view-field--status.html.twig entirely and open an issue to add it back fixing the multilingual issue in views. The entity should be in the language that the row used but it might be tricky to change. And definitely we should not be working around this in the theme layer.
Comment #14
berdirI was also thinking that removing this entirely is something to consider. We would lose the formatting of the status completely though? I'm personally fine with that. removing a feature in default_admin that existed in gin in contrib isn't a regression, but I don't know who exactly needs to make that decision.
Views already has formatting options to display this as Yes/No, a checkbox, or something else, a "Badge" could be another option there?
Comment #15
berdirAlso, we have this "entity status badge" thing as a component in the navigation module for the top bar. This is essentially the same, could be reused if we push it up somewhere (where though...)
Comment #16
jatingupta40 commentedIn addition to the Twig template fix, I'd suggest also hardening `hasTranslation()` in `ContentEntityBase` to guard against null langcodes:
In `/core/lib/Drupal/Core/Entity/ContentEntityBase.php`, add a null coalescing assignment at the start of `hasTranslation()`:
$langcode ??= '';This would make the method more defensive and prevent the deprecation from surfacing even if a null langcode is passed from other places in the future — complementing whatever fix is applied at the template or views layer.
Comment #17
poker10 commentedFWIW, the same warning is also displayed on
/admin/content/filespage, but will disappear on a second page load (until caches are cleared again).Comment #18
idebr commentedUpdated the issue title to more accurately pinpoint the problem
Comment #19
idebr commentedThe merge request now removes the problematic views-view-field--status.html.twig template and its associated styling per #12 / #13. I created a followup issue to implement entity status formatting for views fields, see #3608223: Add entity status formatting to views field
The Proposed resolution is now to remove the twig template instead of updating it
Comment #20
jurgenhaasRemoving this entirely may be problematic, it has been one of those feature that made Gin to be attractive and would be a sort of regression for DCMS who will be switching over when it's no longer experimental.
In Gin, we have MRs 758, 785, and 788, but haven't decided yet which path to follow.
For default_admin following the status badge from the navigation module seems to be the most logical approach.
Comment #21
andypostComment #22
rgpublicI think this is relatively urgent and if no proper fix can be decided on soon, at the very least this file should be removed for the time being with the next GIN update. As I commented under #3580668, a temporary fix is to delete the "themes/gin/templates/views/views-view-field--status.html.twig" but we have dozens of sites and because this error usually occurs within a loop, all errors logs are completely inundated with this error. I've already manually deleted a file for the "worst offending" sites, but a GIN update without a fix for this would make this error reappear, of course. So this could quickly turn into a very unpleasant whack-a-mole I'm afraid - so that's why I'd suggest removing it until a proper fix is decided on.
Comment #23
jurgenhaas@rgpublic this is not the right issue to discuss Gin topics. You're welcome to contribute to the process over in the Gin issue queue to find a conclusion of how to process with the 3 MRs that I linked to above. The matching issues are #3576477: Langcode not correctly detected in field--status which leads to PHP8.5 deprecation issue, #3583491: Using null as an array offset is deprecated error on admin/content and admin/people, and #3591598: row.node_field_data_langcode in views-view-field--status.html.twig may be null. And if you want to make your described workaround persistent, you can add the command to delete a file after each update as a post update script in your composer.json.
Comment #25
jurgenhaasI've opened a new MR!16557 with a proper implementation of the status field twig template for views, instead of removing the entire feature. I've also added tests, for those I've used the help of Opus 5, but reviewed them carefully to make sure they're all reasonable.
What the MR does is to provide a preprocess hook for the status field in views. It provides a boolean and nullable variable that contains the information if the entity contained in the views row is published or not. Should the row not contain an entity, or an entity that has no published key, then that variable is set to NULL. The twig template can then be simplified to only to its magic with the status marker if that variable is either TRUE or FALSE.
Comment #27
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. The merge request has merge conflicts and cannot be merged. 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 #28
jurgenhaasRebased the MR.
Comment #29
andypostThe code looks good to go but not sure about BC policy for twig templates
Comment #30
jurgenhaas@alexpott the only twig file being changed is in default_admin, same for the new hook. And that theme doesn't have any BC commitments, at least not at this point, I'd say.
Comment #31
smustgrave commentedFor twig templates I've always taken the stance they need a CR. If you maintain a contrib theme it's the only way I know to get that message out that a template changed.
Comment #32
jurgenhaas@smustgrave even if the theme is still experimental and the change is just a bug fix that behaves like before but avoids a warning under certain circumstances?
Comment #33
boromino commentedThe twig template and preprocess work and make sense, in general.
However, I propose the following changes:
The preceding code is also used in FieldPluginBase::getEntity(), although with a slightly different syntax. To change FieldPluginBase::getEntity() is out of scope of this issue, but could be done later. Anyway, a separate function would meet Single Responsibility Principle and the function could be later reused in FieldPluginBase or elsewhere.
The explanatory comments (why we avoid getEntity(), why we check the key) don't disappear entirely. They move onto the helper doc blocks.
Comment #34
boromino commentedComment #35
jurgenhaasGreat suggestions, thanks @boromino. I've applied those to the current MR, please have another look.
Comment #36
boromino commentedCode looks good and works, tests pass.
Comment #40
berdirI'm kind of OK with whatever quick fixes we want to add to get rid of the PHP deprecation messages. I'm not so sure about the field map based approach in the most recent MR, I think there's an ongoing discussion on whether or not we want to keep that field map at all. It's expensive to build on a cold cache for one thing, but also, that's just checking if it's boolean. I think the published entity key in the previous MR was deliberate, we do not want to display "Published" on something that's not actually a published key.
I still think we should explore as a follow-up what I wrote in #14. Views has configurable formatter that can display a boolean field as Yes/No, checkmarks and other options, see \Drupal\Core\Field\Plugin\Field\FieldFormatter\BooleanFormatter::getOutputFormats(). IMHO, this kind of output shouldn't be some hardcoded magic in a template, it should be something that's explicitly configured for these views. Gin didn't have that option, default_admin however does since it is in core.
Comment #41
godotislateHad a couple thoughts on MR 16557:
userentity type does not implementEntityPublishedInterfacenor does it have apublishedkey, so it looks like this:On one hand, the issue with user could be fixed in a separate issue to make the entity type implement the interface and add the key, but that won't handle other entity types that are similar. And my thinking is that a status field that has boolean values is going to represent the published status a great majority of the time. So originally, I refactored the preprocess a bit to check whether the field had only boolean-like values, but then I realized that could just be done in the template.
The template only alternative approach is MR 16769.
Though now I prefer the template only alternative, I finished reworking the preprocess approach, so that instead of checking for boolean values, it checks the field map to see if the field is a boolean. This alternative is MR 16768. This handles edge cases better than the template only approach does, but it does have drawbacks as mentioned in #40.
Either of these alternatives handle the user status field correctly:

I agree with this, though it would mean reconfiguring some existing admin views.
For now, I think the template-only approach in MR 16769 is the minimal fix to address the PHP warning without regression.
I do wonder if the new kernel test might be more extensive than needed, but I've exhausted the brain power I have for today on this.
Comment #42
berdir> For now, I think the template-only approach in MR 16768 is the minimal fix to address the PHP warning without regression.
I think it's questionable what exactly the expected and correct behavior is. Your screenshot doesn't replicate HEAD, it actually goes further and fixes it, on HEAD file and user views are not using green pills, they are always grey. I think both the template fix and your other MR now make those green too. Which I guess is fine, but I'd rather not have pills than pills that never change their color.
I'm not sure if it should be limited to published entities or not, it kind of makes sense on user and file, agreed. They don't use a published key on purpose, as users/files aren't published, it means something else for them. You use the field map to avoid the get entity part, but we have an existing API for thata on \Drupal\views\Plugin\views\field\FieldPluginBase::getEntity, which is the base class of EntityField, so we can just call that? And then we can check the field type on that and avoid the field map at runtime.
I'm honestly fine with any of those version as long as we clean it up and avoid performance issues, if we create a follow-up issue to move this into views. One reason for that is that this is still hardcoded for a field named "status". It wouldn't work on \Drupal\menu_link_content\Entity\MenuLinkContent for example, which uses "enabled" for it's published key (we don't really have a use case for MenuLinkContent views, it's just an example)
Comment #43
berdirComment #44
jurgenhaasI've tested both MRs from @godotislate and can confirm that they both work. MR!16768 in particular does use the pills and they correctly switch color both on content and user on main. That would be my preference moving forward for the quick-fix.
Other than that, @berdir's suggestion in #14 should be the proper solution, i.e. delegating this to a views-field formatter, updating the views for new installations, and removing the field template from default_admin.
I leave this on NW as I'm uncertain what's still open, @berdir?
Comment #45
berdirIf the result of MR 16768 is preferred then my suggestion is to to that without the field map, using the existing getEntity() method that we can use and then checking the type through the field definitions.
Comment #46
godotislateI had a typo in previous comment, so correcting here:
MR 16768 uses preprocess with the field map. The reason it use the field map is that in the original MR 16557, there is a comment about why
getEntity()is essentially reimplemented asgetResultRowEntity()in the Hooks class, because getEntity() can trigger log messages if the row does not have an entity. Though EntityField::getValue() actually calls getEntity() anyway, so I don't think we needgetResultRowEntity()(or the field map) at all. If MR 16768 is preferred, I can make the requested changes.MR 16769 is the template-only approach. No preprocessing required.
Just wanted to confirm which one we want to go forward with. Both 16768 and 16769 display the green/gray pills correctly for users and files. (I prefer the template-only approach, but I'm fine with either.)
Comment #47
berdirI care about not using getFieldMap() for now, see #3565128: Avoid calls to EntityFieldManager::getFieldMap() where unnecessary, other than that, no strong opinion. No idea if the template only approach would trigger on something that is unexpected, in theory it could, but it probably doesn't hurt too much and we can always point to the to-be-created follow-up if someone doesn't like it.
And yes, something else would almost certainly trigger those log messages anyway, it's fallback and should not happen on regular cases (it can happen with inconsistent data and race conditions when entities are being deleted while the view is rendered, I've seen that load tests for example.
Comment #48
godotislateOK, removed field map from https://git.drupalcode.org/project/drupal/-/merge_requests/16768.
Comment #49
jurgenhaasMaybe I'm confusing myself just now, but I was looking back to the original template-only code and got reminded, that the root cause was that the template tried to optionally load the translated entity before determining the publishing status:
And that failed for views that haven't been node-based. Are we missing that functionality by now? It seems like we do not bother about that translated entity any longer.
Comment #50
godotislateEntityField::getValue()gets the translated entity. In the template, thefieldvariable is the field handler, androwis the result row, so callinggetValue()gets the correct translated value ifstatusis an entity field.The test coverage for it was also copied from the original MR: https://git.drupalcode.org/project/drupal/-/merge_requests/16769/diffs?f...
Comment #51
jurgenhaasThanks @godotislate, looks like I stopped seeing the forest for all the trees.
I've now reviewed both your MRs again, and tested them on latest main. All looks great and works as described. For some reason I still prefer MR!16768, but I'd be OK with MR!16769 too.
Comment #53
godotislateFair enough, let's go forward with MR!16768. Closing MR!16769.
Comment #54
godotislateAdding the follow up tag so it's not forgotten.
Comment #55
berdirCreated #3619121: Support colored status badge in boolean formatter instead of only in default_admin
Comment #56
quietone commentedRemoving admin theme from the title because this is in the Admin theme component
Comment #57
alexpottThis looks like a pragmatic solution and we've opened follow ups to address this in a better way in the future.
Committed and pushed 51ff2c2fe01 to main and fb9137bc7e8 to 11.x and e2a8f121795 to 11.4.x. Thanks!