-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow for passing stylesheet to wp_theme_has_theme_json
.
#45955
base: trunk
Are you sure you want to change the base?
Conversation
Open in CodeSandbox Web Editor | VS Code | VS Code Insiders |
// Look up the parent if the child does not have a theme.json. | ||
if ( 0 === $theme_has_support ) { | ||
$theme_has_support = is_readable( get_template_directory() . '/theme.json' ) ? 1 : 0; | ||
$wp_theme = wp_get_theme( $stylesheet ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See conversation about performance of wp_get_theme
at https://github.com/WordPress/gutenberg/pull/45831/files#r1029225791
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest, I think this conversation about performance of wp_get_theme
has blown out of proportion a little. Yes, if we can avoid calling it 5 times in a single function, we should rather call it once and put it in a variable.
However, that is a micro optimization that I don't think is critical. I haven't seen any performance testing that would show us it is truly a concern; of course instantiating an object over and over is more expensive than not instantiating the object again, but to me this seems more like a nit-pick concern that won't matter for actual performance.
In other words, it is fine to introduce a call to wp_get_theme
. Just don't call it when you don't have to. In any case, I think here we don't have to (see my overarching feedback).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@felixarntz YES! In this case, we call it once and after that, we cache. This is called once per page load. Making it fine. Calling it 5k times per page is the problem.
@@ -85,7 +86,7 @@ function gutenberg_get_global_styles_svg_filters() { | |||
} | |||
} | |||
|
|||
$supports_theme_json = wp_theme_has_theme_json(); | |||
$supports_theme_json = wp_theme_has_theme_json( $stylesheet ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to do this? Isn't this code querying for the active theme (hence, no need for stylesheet)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This saves a another lookup to get_option
. We have the stylesheet to hand, so why not just pass it in and save a lookup to cache.
if ( $can_use_cached ) { | ||
$cached = get_transient( $transient_name ); | ||
if ( $cached ) { | ||
return $cached; | ||
} | ||
} | ||
$tree = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data(); | ||
$supports_theme_json = wp_theme_has_theme_json(); | ||
$supports_theme_json = wp_theme_has_theme_json( $stylesheet ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to do this? Isn't this code querying the active theme (hence, no need for stylesheet)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if ( empty( $stylesheet ) ) { | ||
$stylesheet = get_stylesheet(); | ||
} | ||
$cache_key = sprintf( 'wp_theme_has_theme_json_%s', $stylesheet ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see two issues with caching by theme:
- Code complexity: what are the benefits of having cache keys per theme when we only need one at a time?
- I don't see a way to clean the cache key for the previous theme upon a
start_previewing_event
. It gives the stylesheet of the theme being previewed, but at that point we need to clear the cache key of the previous theme, not the one being previewed. How can we do this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Complexity is not really a good argument not to do something. Just becuase it is hard, does not mean it not worthwhile. I have done the hard work to make this work, let's go ahead here.
Good point about start_previewing_event
. This cache clearing can be removed, as now the cache key will be different once you start previewing, which is pretty neat. I am not against removing this all together, but I kept, just in case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Complexity is not really a good argument not to do something. Just becuase it is hard, does not mean it not worthwhile. I have done the hard work to make this work, let's go ahead here.
My point is not about doing something that is hard. It is about not doing something complex when it can be simple.
This approach is more complex in terms of code and more demanding in terms of memory (we store cache keys we don't need instead of one). The direction I shared a while ago and summarized here again is simpler and brings bigger performance gains. Would you be willing to give it a try and reevaluate when is it shipped?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand this feedback at all. For most requests, it will only store one cache key, like it does currently. There difference here, is this structure all for multiple themes theme json to be required. This makes cache invalidation easier, not harder.
Where is the there a performance lose here?
function wp_theme_has_theme_json_clean_cache() { | ||
wp_cache_delete( 'wp_theme_has_theme_json', 'theme_json' ); | ||
function _wp_theme_has_theme_json_clean_cache_start_previewing_theme( $manager ){ | ||
wp_theme_has_theme_json_clean_cache( $manager->get_stylesheet() ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See https://github.com/WordPress/gutenberg/pull/45955/files#r1029244275 we need to clear the cache of the previous theme, not the actual one.
* @param WP_Theme $old_theme WP_Theme instance of the old theme. | ||
*/ | ||
function _wp_theme_has_theme_json_clean_cache_switch_theme( $new_name, $new_theme, $old_theme ) { | ||
wp_theme_has_theme_json_clean_cache( $new_theme->get_stylesheet() ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* Bail early if the theme does not support a theme.json. | ||
* | ||
*/ | ||
if ( ! wp_theme_has_theme_json( $theme->get_stylesheet() ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these inner private methods should not hold this kind of domain logic. It should be the consumer responsibility to ask for the data they need. This is how I envision improving on the current situation:
- 1st step is making the
get_merged_data
method work properly (take into account the origin) Merged data should consider origin to return early #45969 - 2nd step is modifying the public methods to ask for the proper origin of data they want. Example for the settings Update which origins are queried for
gutenberg_get_global_settings
#45971
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On this we disagree. The current system of origin, is hard to understand, hard to test and VERY unclaer from a development standpoint. We should be moving away from this pattern and the code easier to use any understand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fundamental issue with adding caching to the resolver instead of adding it to the public methods is this: every public method has different conditions for cache invalidation. settings & styles need some, theme.json check needs some other, and patterns/custom templates need totally different conditions.
We cannot simply replicate those invalidations within the resolver. That was the core issue we ran into in the WordPress 6.1 cycle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method get_user_data_from_wp_global_styles
take a param of WP_Theme
, we need to respect that and check the requested them support theme.json.
Look at this method in core. https://github.com/WordPress/wordpress-develop/blob/9ed27339b19eb07aa01bcb7e593be2e11f928f1e/src/wp-includes/class-wp-theme-json-resolver.php#L423-L425
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@felixarntz add this change. Can you chime in here.
$parent_theme_json_file = static::get_file_path_from_theme( 'theme.json', true ); | ||
if ( '' !== $parent_theme_json_file ) { | ||
$parent_theme_json_data = static::read_json_file( $parent_theme_json_file ); | ||
if ( wp_theme_has_theme_json( $wp_theme->parent()->get_stylesheet() ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@felixarntz @oandregal Is the perfect example of why we need this function to allow for passing a stylesheet. In this context, we need to know if the parent ( not the current ) theme has theme json. This is need for every request, making this change required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@oandregal @spacedmonkey Chiming in here late, I see both of your concerns:
- I agree with you @spacedmonkey that we should provide a way to find out whether a theme has
theme.json
for any theme, not just the current theme. - I also agree with you @oandregal that changing this
wp_theme_has_theme_json()
function to support any theme should not be necessary.
The main use-case surely is the current theme. However, WordPress has always provided ways to get the same information for any theme, so we should work on that too. But my main feedback is that those things should happen in different places to align with how WordPress core works today.
Consider the following: WordPress core today has theme functions, those typically work only for the current theme. But it also has the WP_Theme
class that provides methods to get the same data for any theme (whatever you instantiate the WP_Theme
with, via wp_get_theme()
).
Some examples:
get_stylesheet()
vsWP_Theme::get_stylesheet()
get_template()
vsWP_Theme::get_template()
get_template_directory()
vsWP_Theme::get_template_directory()
get_theme_file_path()
vsWP_Theme::get_file_path()
In all of the above, the function is always for the current theme (no parameter), and the method works for whatever WP_Theme
is instantiated as. In other words, I would propose we follow the same approach:
- Keep
wp_theme_has_theme_json()
simple, without a parameter and without having to usewp_get_theme()
. - Introduce a method
WP_Theme::has_theme_json()
that allows doing the same for any theme.
That's my 2 cents.
// Look up the parent if the child does not have a theme.json. | ||
if ( 0 === $theme_has_support ) { | ||
$theme_has_support = is_readable( get_template_directory() . '/theme.json' ) ? 1 : 0; | ||
$wp_theme = wp_get_theme( $stylesheet ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest, I think this conversation about performance of wp_get_theme
has blown out of proportion a little. Yes, if we can avoid calling it 5 times in a single function, we should rather call it once and put it in a variable.
However, that is a micro optimization that I don't think is critical. I haven't seen any performance testing that would show us it is truly a concern; of course instantiating an object over and over is more expensive than not instantiating the object again, but to me this seems more like a nit-pick concern that won't matter for actual performance.
In other words, it is fine to introduce a call to wp_get_theme
. Just don't call it when you don't have to. In any case, I think here we don't have to (see my overarching feedback).
I believe we will need this change for #45371 which is part of Phase 2: Customization |
567f818
to
4ed8ce5
Compare
@spacedmonkey Per my comment in #45955 (review), I still don't think this is a good idea. IMO we should rather introduce a |
Part of #45171
What?
Allow stylesheet to
wp_theme_has_theme_json
. This allows for the developers to check if none active themes support theme json. This also improves caching, as caches are no longer depending on current theme.See #45950 #45831
Why?
How?
Testing Instructions
Screenshots or screencast