Problem/Motivation

Follow-up from #2173655: Refactor theme() to _theme(); make it a private API to discourage module developers from circumventing the renderable build system.

The docblock for _theme() discourages the user from calling _theme() directly, but does not clearly indicate that this will now break things. #2173655: Refactor theme() to _theme(); make it a private API to discourage module developers from circumventing the renderable build system renames the function to _theme() to indicate that it's a private function only.

Proposed resolution

Update the API docblock for _theme() to clearly indicate that _theme() is for internal use within drupal_render() only and explain what will break if this is not respected:

Calling the theme() function directly raises several issues:

  • Circumvents caching.
  • Circumvents defaults of types defined in hook_element_info(), including attached assets
  • Circumvents the pre_render and post_render stages.
  • Circumvents JavaScript states information.

Remaining tasks

This issue is postponed on #2173655: Refactor theme() to _theme(); make it a private API to discourage module developers from circumventing the renderable build system.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

xjm’s picture

Issue summary: View changes
star-szr’s picture

Issue tags: +Twig

Tagging for rocketship. Thanks @xjm!

catch’s picture

Status: Postponed » Active
nicksanta’s picture

Patch attached which melds the existing relevant paragraph with additional details provided in issue summary.

nicksanta’s picture

Status: Active » Needs review
jhodgdon’s picture

Status: Needs review » Needs work

This looks pretty good. The only thing I was not sure about was the first sentence:

+ * Avoid calling this function directly as it raises several issues:

This doesn't seem quite strong enough. I think rather than "avoid calling" we should say "Don't call", and rather than "raises several issues" we need to get across the concept of "doesn't work" explicitly?

I also wonder if at the end we should mention just returning a renderable array wherever possible rather than even having to call drupal_render() explicitly?

longwave’s picture

Status: Needs work » Needs review
FileSize
997 bytes

I reworded the paragraph to be even stronger.

longwave’s picture

FileSize
999 bytes

Oops, it's a function, not a method.

nicksanta’s picture

FileSize
1.08 KB

I've adapted patch from #8 with some changes.

  • I find the itemised list more readable, rather than a run-on sentence.
  • A problem was omitted from the list - "Circumvents defaults of types provided by hook_element_info(), including attached assets."
xjm’s picture

+++ b/core/includes/theme.inc
@@ -406,10 +406,14 @@ function drupal_find_base_themes($themes, $key) {
+ * Do not call this function directly as it will prevent the following items ¶

Teeny bit of trailing whitespace.

The improved documentation looks great. Thanks @longwave! Can we also rewite the paragraph preceding this one in the _theme() docblock? There's still a sentence in there starting with "However..." that is misleading. In general, I think we should emphasize that the function is used internally in drupal_render().

There's also a lot of other documentation on _theme()'s docblock following that that we need to consider updating and/or or moving to a public API function, I think.

xjm’s picture

Status: Needs review » Needs work
jhodgdon’s picture

The other documentation on theme() or _theme() is a description of all of the hooks that are called during theming/rendering. It seems like a logical place to move this might be to drupal_render(), or else to a @defgroup/topic might be even better?

We do not currently have a topic for the theme or render system, but on #2148255: [meta] Make better D8 api.d.o landing page, linked to high-level overview topics, and put it in Core api.php files a skeleton topic is proposed. That would be a good place to put this information (and, hint hint, that patch needs a review!).

jessebeach’s picture

Status: Needs work » Needs review
FileSize
1.73 KB
1.78 KB

For the purposes of this particular issue, the changes in #9 should be satisfactory. The change clearly states that _theme() should not be called directly and then explains the consequences of calling it directly.

I agree with jhodgdon in #12 that a good hunk of the _theme() docblock is poorly located. We shouldn't have usage information associated with the function that we recommend not be called directly. The docs are accurate, just poorly placed. But the poor placement should not be considered a beta blocker. Moving the doc is just a normal task. I've created that issue to address it:

#2215587: _theme() is now an internal function; Move the Theming documentation to a better-suited page in the documentation

The attached patch addresses xjm's comment in #10 about the lingering "however" in the docblock.

xjm’s picture

Status: Needs review » Reviewed & tested by the community

I agree with splitting off the theme documentation group part into a separate non-beta-blocker.

The updated patch looks great. I also reviewed the whole docblock with the patch applied to make sure everything is accurate and makes sense.

xjm’s picture

Status: Reviewed & tested by the community » Needs review

Whoops, I just happened to look in theme.api.php for the followup issue, and found this:

Calling the _theme() function directly is highly discouraged. Building a renderable array is preferred. For example, rather than calling _theme('table', array()) in-place, one can assemble a renderable array as follows:

We need to update that bit too.

jessebeach’s picture

So, changing the bit of text mentioned in #15 was quite the thread in a sweater or, the veritable giving a mouse a cookie. I ended up having to move _theme() function doc block over to theme.api.php in order to have the text make any sense. Which means we can effectively close #2215587: _theme() is now an internal function; Move the Theming documentation to a better-suited page in the documentation.

xjm’s picture

+++ b/core/modules/system/theme.api.php
@@ -9,74 +9,105 @@
+ * Note that calling the _theme() function directly is highly discouraged.
+ * Building and returning a renderable array in a page build process is
+ * preferred. If necessary, the array may be rendered to a string in-place

Can we change this to say: "Do not call _theme() directly; instead, build and return a renderable array. If necessary..."

jessebeach’s picture

FileSize
15.49 KB
668 bytes

Yes, that's much more direct.

jhodgdon’s picture

Status: Needs review » Needs work

Since _theme() is for internal use, do you think it would make sense to change its first-line summary from "Generates themed output." to something like "Generates themed output (internal use only)."? I'm OK either way, but if you are striving for clarity on this point...

Another thing to fix: In the theme.api.php section of the patch, you're patching the topic for @defgroup themeable.

So ... a ways down, it says:

+ * @section sec_theme_hooks Theme Hooks
+ * Most commonly, the first argument to this function is the name of the theme
+ * hook. For instance, to theme a taxonomy term, the theme hook name is
...

That was taken from the old theme() docs, where it made sense, but here it doesn't, because we're not using a call to theme(), we're using a #theme element in a render array.

There are probably some more things that need fixing... I need to run off but I don't think we want to just blindly copy/paste this text from theme() into this new location. Sigh.

Oh, one more thing that we can't commit this with: in the _theme() docs, it says:

+ * All requests for themed output must go through this function, which is
+ * invoked as part of the @link theme_render drupal_render() process @endlink.

I do not think this topic "theme_render" exists anywhere in core. Were you going to create it (at least as a stub)?

jessebeach’s picture

Status: Needs work » Needs review
FileSize
15.59 KB
5.14 KB

I pulled theme_render from #2148255: [meta] Make better D8 api.d.o landing page, linked to high-level overview topics, and put it in Core api.php files, which is now RTBC.

Since _theme() is for internal use, do you think it would make sense to change its first-line summary from "Generates themed output." to something like "Generates themed output (internal use only)."?

Yes, I support completely any language that discourages use of _theme() in modules or themes. When I started using Drupal, I was very confused about whether I should use drupal_render() or theme(). We need very clear documentation about _theme() -- that it should not be used by contrib developers.

The changes in this patch should hopefully discourage the direct use of _theme() while explaining the concepts of theme hooks, templates and overrides.

jhodgdon’s picture

I think this looks really good. There's a small wrapping issue in the theme.api.php segment of the patch:

+ * To invoke a theme implementation on a renderable array, define a key named
+ * '#theme' and assign it a string value that is the name of a
+ * theme hook. Any variables that the theme hook requires
+ * may be supplied as additional keys -- prepended with a '#' character -- in
+ * the renderable array.

(should be wrapped closer to 80 characters) but I would be OK with this going in without fixing this if we need to get this critical in.

jessebeach’s picture

FileSize
15.58 KB
863 bytes

Easy enough to fix right now :)

The last submitted patch, 20: _theme-docs-2191107-20.patch, failed testing.

jhodgdon’s picture

Status: Needs review » Reviewed & tested by the community

Thanks! Let's get this in then.

webchick’s picture

Status: Reviewed & tested by the community » Fixed

Excellent work. Another beta blocker bites the dust, and docs are improved along the way!

Committed and pushed to 8.x. Thanks!

Status: Fixed » Closed (fixed)

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