Problem/Motivation

Theme functions were deprecated back in 8.1.x and slated for removal in Drupal 9. However, we improved our deprecation policy during the lifecycle of Drupal 8 and added warnings to developers; these warnings were never added to the theme function system, and theme functions are still used in Drupal 8 contrib.

Contrib code search: http://grep.xnddx.ru/search?text=function%20theme_&filename=

Proposed resolution

Deprecate theme functions properly using trigger_error() etc for removal in Drupal 9.

OR

Deprecate theme functions properly using trigger_error() etc for removal in Drupal 10.

Remaining tasks

Add the deprecations and tests.

User interface changes

None

API changes

Developers will be warned when they use deprecated theme functions functionality.

Data model changes

None

Release notes snippet

Theme functions were deprecated prior to Drupal 8.8.0's release in favour of Twig templates. However the deprecation did not use Drupal's deprecation APIs to notify module and theme developers. From Drupal 8.9.0 the use of theme functions will start to trigger deprecation notices.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

longwave created an issue. See original summary.

lauriii’s picture

Version: 9.1.x-dev » 8.8.x-dev
Issue tags: +Needs release manager review

Discussed with @catch and @alexpott on Slack since this has some security concerns which creates some urgency around this. The main problem is that theme functions are lacking auto escaping. This makes the developer experience potentially confusing since developers will have to remember when to worry about escaping.

To estimate the disruption, we looked deeper into the the usages of theme functions. A lot of the usages are in modules without any Drupal 8 releases. Some of the modules have releases but theme functions aren't actually called anywhere.

If we want to move forward with this prior to Drupal 9, we should add a proper deprecation in a future release of Drupal 8.8.x so that people can have as much time to remove usages of theme functions as possible. I'm tagging this for release manager review so they can make a final decision on this.

catch’s picture

I did spot checks on a few modules from that grep.

For example xmlsitemap defines a theme function for an admin page, but it's dead code and never used.

Search API also defines a theme function for an admin page, but it is still used.

Several other modules don't have 8.x releases yet (i.e. abandoned 8.x branches with no release on the project page and no recent commits).

So if we deprecate in 8.8.x properly for 9.x we'll force (my guess) 5-10 maintained modules with some usage to do extra work to be 9.x compatible. This is not huge but it is more than nothing given 8.8.0 is already out.

If we don't deprecate for 9.x, I think we should still deprecate in 8.9.x for Drupal 10 to encourage people to actually finish porting from Drupal 7 / security harden, and because it's actually been deprecated for years now just without our full deprecation framework implemented for it.

lauriii’s picture

There could be some themes customizing those theme functions too. It's likely that if a module ships with a theme function, that the override is also a theme function. It seems like that the Search API theme function isn't something that people would override often, but it might be a good idea to look into some of the other modules to try to ensure there aren't any instances that would be commonly overridden by people.

xjm’s picture

What are the security concerns? Or is there a private issue where we can or should be discussing?

longwave’s picture

@xjm I think the security concerns are just that theme functions do not and cannot autoescape their output, making it very easy to inadvertently allow XSS.

xjm’s picture

Priority: Normal » Critical

Let's start working on a patch for this now; we can make the decision about whether to backport a deprecation to 8.8.x for 9.0.x removal vs. backporting for 10.0.x removal once we see what the impacts of the deprecation would be. After chatting with @catch it sounds like the deprecation might be a little involved, since we're not deprecating just a function or method; we're deprecating the ability to create a kind of API.

Meanwhile we should also detect them directly in Upgrade Status I think, because I think a lot of themes and theme functions don't have test coverage in contrib. Let's file an issue for that too.

longwave’s picture

Status: Active » Needs review
FileSize
898 bytes

Trivial patch to get the ball rolling.

Status: Needs review » Needs work

The last submitted patch, 8: 3109480-8.patch, failed testing. View results

longwave’s picture

Status: Needs work » Needs review
FileSize
2.2 KB

So the biggest problems here are two test modules, common_test and theme_test. I think we are safe to remove theme functions from common_test as it is used in multiple places and doesn't test theme functionality directly. This patch does that removal.

theme_test is going to be more complicated. I think the best solution might be to clone it to a theme_deprecated_test module, remove the theme functions from the original, and convert all the deprecated test parts to legacy tests that use the cloned module.

Status: Needs review » Needs work

The last submitted patch, 10: 3109480-10.patch, failed testing. View results

catch’s picture

Second part of #10 sounds like a good plan to me.

longwave’s picture

Status: Needs work » Needs review
FileSize
27.18 KB

Work in progress; the test modules that use theme functions have been split out and ThemeSuggestionsAlterTest has been split up as well, but lots more tests to split up or add @group legacy to.

Running this locally I also seem to still get the new deprecation messages in tests where I don't expect them, need to figure out what is triggering that.

Status: Needs review » Needs work

The last submitted patch, 13: 3109480-13.patch, failed testing. View results

longwave’s picture

Status: Needs work » Needs review
FileSize
33.73 KB
6.75 KB

Still more to do but this should clean up any false positive deprecation messages now.

Status: Needs review » Needs work

The last submitted patch, 15: 3109480-15.patch, failed testing. View results

longwave’s picture

Status: Needs work » Needs review
FileSize
38.85 KB
5.11 KB

Not quite sure what to do with ThemeTest::testPreprocessForSuggestions() and ThemeTest::testNegotiatorPriorities() yet.

Status: Needs review » Needs work

The last submitted patch, 17: 3109480-17.patch, failed testing. View results

longwave’s picture

Status: Needs work » Needs review
FileSize
40.31 KB
2.75 KB

I think it is OK to convert these to Twig as theme function functionality is still tested elsewhere.

Status: Needs review » Needs work

The last submitted patch, 19: 3109480-19.patch, failed testing. View results

longwave’s picture

xjm’s picture

bnjmnm’s picture

I'm beginning a review of the patch in #21 and noticed the issue summary is a little out of sync regarding version numbers. Tagging to "needs issue summary update" (would typically just update it myself but there's just enough potential to add something incorrect that I'd prefer someone who has been active in the issue )

catch’s picture

@bnjmnm so it's inconsistent because we're a bit undecided. But I think it makes sense to write a patch for 9.0.x removal and the version numbers are the easiest thing to change if we end up deciding to deprecate for 10.0.x instead.

catch’s picture

@bnjmnm so it's inconsistent because we're a bit undecided. But I think it makes sense to write a patch for 9.0.x removal and the version numbers are the easiest thing to change if we end up deciding to deprecate for 10.0.x instead.

bnjmnm’s picture

Makes sense regarding the issue summary, removing the tag since the need to update isn't certain until this exits undecided status.

I plan to do a full review but providing a partial one for now as I may not be able to resume until tomorrow.

  1. +++ b/core/modules/system/tests/modules/theme_deprecated_test/src/ThemeTestController.php
    @@ -0,0 +1,38 @@
    + * Controller routines for deprecated theme test routes.
    
    +++ b/core/modules/system/tests/src/Functional/Theme/DeprecatedThemeSuggestionsAlterTest.php
    @@ -0,0 +1,73 @@
    + * Tests deprecated theme suggestion alter hooks.
    

    These could be misinterpreted as the routes/hooks themselves being deprecated. Could these comments be rephrased? (may be additional instances of this in the patch)

  2. +++ b/core/modules/system/tests/modules/theme_deprecated_suggestions_test/theme_deprecated_suggestions_test.info.yml
    @@ -0,0 +1,5 @@
    +name: 'Theme suggestions test'
    +type: module
    +description: 'Support module for testing theme suggestions.'
    +package: Testing
    +version: VERSION
    

    Could this be updated to reflect that it's specifically testing suggestions that make use of deprecated theme functions?

  3. Although it should be pretty evident that theme_deprecated_test and test_deprecated_theme will require removal when theme functions are removed, including a @todo to (I think?) #3097889: Remove deprecated theme functions will make this more transparent.
  4. +++ b/core/modules/system/tests/modules/theme_deprecated_suggestions_test/theme_deprecated_suggestions_test.module
    @@ -0,0 +1,32 @@
    +    'variables' => [],
    

    'variables' isn't needed.

  5. +++ b/core/modules/system/tests/themes/test_theme/templates/theme-test--suggestion.html.twig
    index a5af83bc87..109ff44d22 100644
    --- a/core/modules/system/tests/themes/test_theme/test_theme.theme
    
    --- a/core/modules/system/tests/themes/test_theme/test_theme.theme
    +++ b/core/modules/system/tests/themes/test_theme/test_theme.theme
    

    There's a theme function test_theme_theme_test_function_suggestions__module_override still in this file that should be moved, or if it can't there should be a comment explaining why and a @todo to remove when theme functions are removed.

  6. +++ b/core/modules/system/tests/modules/common_test/common_test.module
    @@ -123,25 +123,10 @@ function common_test_theme() {
         'common_test_empty' => [
           'variables' => ['foo' => 'foo'],
    -      'function' => 'theme_common_test_empty',
         ],
    

    common_test_empty and the accompanying template can be removed entirely. I had my suspicions but didn't want to suggest until I confirmed this by creating a test patch and drupalci was fine with it.

bnjmnm’s picture

Status: Needs review » Needs work

Here's the rest of the review. Looks like pretty minor stuff.
Tried to avoid too much scrutiny on code that was clearly just moved and not original to this patch - my goal there was to confirm the right things were properly moved to the right place as opposed to relitigating tests that will be removed shortly(?). #26.4 was an exception to this.

  1. +++ b/core/modules/system/tests/src/Functional/Theme/ThemeTest.php
    @@ -143,8 +143,12 @@ public function testTemplateOverride() {
       /**
        * Ensures a theme template can override a theme function.
    +   *
    +   * @group legacy
        */
       public function testFunctionOverride() {
    +    \Drupal::service('module_installer')->install(['theme_deprecated_test']);
    +
    

    Although it should be pretty clear what is going on when theme_deprecated_test is removed, adding a @todo to the issue where that will occur will make things clearer.
    Would be helpful to do this in the unit and kernel RegistryTest as well.

  2. Several other tests with @group legacy were renamed (testName)LegacyTest. That naming approach may help mitigate some of the confusion with the use of "deprecated" I mentioned earlier.
longwave’s picture

Status: Needs work » Needs review
FileSize
42.97 KB
26.62 KB

Thanks for the detailed review!

#26.1, #26.2, #27.2: I reworded a number of comments and renamed "deprecated" things to "legacy" which hopefully makes it clearer.

#26.3, #27.1: Added @todos pointing to the removal issue.

#26.4, #26.6: Removed these.

#26.5: This and two other functions have been moved to the legacy theme that will be deleted entirely in the future.

bnjmnm’s picture

Status: Needs review » Needs work

#28 is looking good! One additional thing came to mind - there should be test coverage for the deprecation itself . A test similar to \Drupal\Tests\Core\Asset\LibraryDiscoveryTest::testAssetLibraryDeprecation would provide the necessary coverage.

longwave’s picture

Quick question: as the change record predates 8.0.0 should the deprecation message start "Theme functions are deprecated in drupal:8.0.0" even though we are introducing this much later?

Looking at the diff again I also think I want to refactor the tests even further to make the legacy tests even simpler to delete in the followup, will try to get to that and #29 in the next day or two.

longwave’s picture

Status: Needs work » Needs review
FileSize
47.48 KB
18.54 KB

Refactored all the tests; we now have legacy unit, kernel and functional tests which will be simple to remove later. #29 is solved by using @expectedDeprecation in the unit and kernel tests to confirm the deprecation is triggered correctly.

I also answered my own question in #30; elsewhere we mark deprecations as "in drupal:8.0.0" even if the actual deprecation was added much later, so I reworded the deprecation here to start from 8.0.0 as well.

longwave’s picture

Fixed up some comments.

catch’s picture

I also answered my own question in #30; elsewhere we mark deprecations as "in drupal:8.0.0" even if the actual deprecation was added much later

Yes it should be the version that the functionality was deprecated rather than the version we added the deprecation notice usually - as if we'd had a fully-worked-out deprecation process at the time.

bnjmnm’s picture

All my feedback from #31 and #32 is nicely addressed. I did an additional round of manual test runs where I intentionally changed and removed things to confirm the tests work and that no unnecessary code is present and it was in good shape.

The patch itself seems RTBC worthy at this point but it seems like it would be best to hold off until this gets release manager review/policy specifics. If I'm incorrect on that rationale let me know and I'll change the status.

catch’s picture

So IMO removing support for this in 9.x is still a good idea - theme functions can't use Twig autoescape, which was why we deprecated them in 8.x in the first place.

We have a change record for this from 2015: https://www.drupal.org/node/2575445

catch’s picture

Issue summary: View changes
bnjmnm’s picture

Tagging with Drupal 9.0.0-beta1 requirement so this can be visible in a search vs just via the parent issue.

lauriii’s picture

Status: Needs review » Reviewed & tested by the community

The deprecation message looks good. I also checked that no test coverage is lost by the change. Besides that, I applied only the change for Drupal\Core\Theme\Registry and ran Drupal\KernelTests\Core\Theme\RegistryTest to ensure the deprecation error is thrown.

It also looks like @catch is feeling positive about this change so I'm moving this to RTBC to wait for a final decision from the release managers.

longwave’s picture

This applies to all three branches for me (with fuzz), adding tests just to be sure.

Gábor Hojtsy’s picture

Just noting based on chat discussion that @catch is awaiting feedback from @xjm to make sure both release managers are on board with the target version of the deprecation especially.

xjm’s picture

Based on the extent of http://grep.xnddx.ru/search?text=function%20theme_&filename= I'm not totally comfortable deprecating this for removal before 9.0.0. I think it should have been done before 8.8 for it to be a 9.x deprecation.

If we're concerned about the security impact of this (and I am), we could deprecate for 10.0.x, but backport it to 8.9.x or even 8.8.x as an exception to the general "9.1.x" policy, and potentially follow the approach we used for string formatting placeholders and trigger_error() with no @ in 9.0.x.

Gábor Hojtsy’s picture

Status: Reviewed & tested by the community » Needs work
xjm’s picture

Issue tags: +Needs followup

@catch proposed simply changing the deprecation to 10.0.x here, backporting it to at least 8.9.x, and filing a followup to remove the @ from the trigger_error() in 9.0.x only.

Gábor Hojtsy’s picture

Title: Deprecate theme functions » Properly deprecate theme functions for Drupal 10

Retitling for clarity.

catch’s picture

Status: Needs work » Needs review
FileSize
47.56 KB

Just did a find and replace for s/9.0.0/10.0.0/g

longwave’s picture

Issue tags: -Needs followup

#46 looks good.

Opened #3117330: Trigger errors in deprecated theme functions to follow up in 9.0.x.

Can we remove the "needs release manager review" tag now?

longwave’s picture

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

Removing tag.

alexpott’s picture

Status: Reviewed & tested by the community » Patch (to be ported)

This looks great. Yay for proper deprecation testing and @trigger_error!

Leaving open against 8.8.x as we might commit it there once 8.8.3 is out.

Committed and pushed 4a70ba3774 to 9.0.x and f8870768f5 to 8.9.x. Thanks!

  • alexpott committed 4a70ba3 on 9.0.x
    Issue #3109480 by longwave, catch, bnjmnm, xjm, lauriii, Gábor Hojtsy:...

  • alexpott committed f887076 on 8.9.x
    Issue #3109480 by longwave, catch, bnjmnm, xjm, lauriii, Gábor Hojtsy:...
mondrake’s picture

Status: Patch (to be ported) » Needs work

I am afraid this has broken testing on PHPUnit CLI for groups:

$ $DRUPAL_PATH/vendor/bin/phpunit $TEST_ARGS

PHP Fatal error:  Cannot redeclare Drupal\Core\Theme\get_defined_functions() (previously declared in /home/travis/drupal8/core/tests/Drupal/Tests/Core/Theme/RegistryTest.php:503) in /home/travis/drupal8/core/tests/Drupal/Tests/Core/Theme/RegistryLegacyTest.php on line 178
Mile23’s picture

catch’s picture

Status: Needs work » Postponed

We should probably postpone the backport here on #3118477: RegistryTest, RegistryLegacyTest both define the same class, use mock instead, but the fatal error is only an issue if running tests in a very specific way (i.e. not on DrupalCI, and not running them individually, which are the more common), so no reason to roll this back against 8.9.x/9.0.x IMO. Moving to 'postponed'

longwave’s picture

Status: Postponed » Needs work

#3118477: RegistryTest, RegistryLegacyTest both define the same class, use mock instead was committed so NW to incorporate those changes here for 8.8.x.

xjm’s picture

Version: 8.8.x-dev » 8.9.x-dev
Status: Needs work » Fixed

@catch and I discussed this again and agreed not to backport the issue to 8.8.x. New deprecations are minor-only as a rule, and this one in particular could be pretty disruptive. It already caused some confusion that was reported in Drupal Slack just from what's already been committed (which led to #3120954: Add function name to the deprecation message about theme functions being filed).

With the 8.9.x deprecation as well as #3117330: Trigger errors in deprecated theme functions, we're still ensuring that contrib and custom modules are going to find out about this soon.

xjm’s picture

Issue tags: +8.9.0 release notes
phenaproxima’s picture

Status: Fixed » Needs work
Issue tags: +Needs release note

Tagging for a release note and re-opening until we have one.

catch’s picture

Issue summary: View changes
Status: Needs work » Fixed
Issue tags: -Needs release note
catch’s picture

Issue summary: View changes

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.