-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Add plugin template registration API #61577
Changes from all commits
a4f1949
b9d439b
90669a8
e1612d6
8d56d84
1b7292b
474cd8a
9c1016c
d31655f
d9d7bf5
69e340c
736b0a8
5e6719f
83430f5
934d358
e2006a3
93d1698
3f16162
d8b545f
8de5b47
64aad98
e13c5a6
6e11c6b
0a3e58f
94f1f2d
4972b25
231a82b
1082b14
3c4d9ba
c021b3f
1f8274b
469e680
44ce898
ae53a3a
e8fb1ea
de4ac59
00d9f40
9232b1f
81f17c9
ba73c17
3962e67
efc6847
d483308
b76c676
0ec44e1
2c5d734
b5a3de4
336c0a3
7eb235c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
https://github.com/WordPress/wordpress-develop/pull/7125 | ||
|
||
* https://github.com/WordPress/gutenberg/pull/61577 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
<?php | ||
/** | ||
* Block template functions. | ||
* | ||
* @package gutenberg | ||
*/ | ||
|
||
if ( ! function_exists( 'wp_register_block_template' ) ) { | ||
/** | ||
* Register a template. | ||
* | ||
* @param string $template_name Template name in the form of `plugin_uri//template_name`. | ||
* @param array|string $args Object type or array of object types with which the taxonomy should be associated. | ||
* @param array|string $args { | ||
* @type string $title Optional. Title of the template as it will be shown in the Site Editor | ||
* and other UI elements. | ||
* @type string $description Optional. Description of the template as it will be shown in the Site | ||
* Editor. | ||
* @type string $content Optional. Default content of the template that will be used when the | ||
* template is rendered or edited in the editor. | ||
* @type string[] $post_types Optional. Array of post types to which the template should be available. | ||
* @type string $plugin Uri of the plugin that registers the template. | ||
* } | ||
* @return WP_Block_Template|WP_Error The registered template object on success, WP_Error object on failure. | ||
*/ | ||
function wp_register_block_template( $template_name, $args = array() ) { | ||
return WP_Block_Templates_Registry::get_instance()->register( $template_name, $args ); | ||
} | ||
} | ||
|
||
if ( ! function_exists( 'wp_unregister_block_template' ) ) { | ||
/** | ||
* Unregister a template. | ||
* | ||
* @param string $template_name Template name in the form of `plugin_uri//template_name`. | ||
* @return true|WP_Error True on success, WP_Error on failure or if the template doesn't exist. | ||
*/ | ||
function wp_unregister_block_template( $template_name ) { | ||
return WP_Block_Templates_Registry::get_instance()->unregister( $template_name ); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,203 @@ | ||||||
<?php | ||||||
/** | ||||||
* REST API: Gutenberg_REST_Templates_Controller_6_7 class | ||||||
* | ||||||
* @package gutenberg | ||||||
*/ | ||||||
|
||||||
/** | ||||||
* Gutenberg_REST_Templates_Controller_6_7 class | ||||||
* | ||||||
*/ | ||||||
class Gutenberg_REST_Templates_Controller_6_7 extends Gutenberg_REST_Templates_Controller_6_6 { | ||||||
/** | ||||||
* Returns the given template | ||||||
* | ||||||
* @param WP_REST_Request $request The request instance. | ||||||
* @return WP_REST_Response|WP_Error | ||||||
*/ | ||||||
public function get_item( $request ) { | ||||||
if ( isset( $request['source'] ) && ( 'theme' === $request['source'] || 'plugin' === $request['source'] ) ) { | ||||||
$template = get_block_file_template( $request['id'], $this->post_type ); | ||||||
} else { | ||||||
$template = get_block_template( $request['id'], $this->post_type ); | ||||||
} | ||||||
|
||||||
if ( ! $template ) { | ||||||
return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.' ), array( 'status' => 404 ) ); | ||||||
} | ||||||
|
||||||
return $this->prepare_item_for_response( $template, $request ); | ||||||
} | ||||||
|
||||||
/** | ||||||
* Prepare a single template output for response | ||||||
* | ||||||
* @param WP_Block_Template $item Template instance. | ||||||
* @param WP_REST_Request $request Request object. | ||||||
* @return WP_REST_Response Response object. | ||||||
*/ | ||||||
// @core-merge: Fix wrong author in plugin templates. | ||||||
public function prepare_item_for_response( $item, $request ) { | ||||||
$template = $item; | ||||||
|
||||||
$fields = $this->get_fields_for_response( $request ); | ||||||
|
||||||
if ( 'plugin' !== $item->origin ) { | ||||||
return parent::prepare_item_for_response( $item, $request ); | ||||||
} | ||||||
$cloned_item = clone $item; | ||||||
// Set the origin as theme when calling the previous `prepare_item_for_response()` to prevent warnings when generating the author text. | ||||||
$cloned_item->origin = 'theme'; | ||||||
$response = parent::prepare_item_for_response( $cloned_item, $request ); | ||||||
$data = $response->data; | ||||||
|
||||||
if ( rest_is_field_included( 'origin', $fields ) ) { | ||||||
$data['origin'] = 'plugin'; | ||||||
} | ||||||
|
||||||
if ( rest_is_field_included( 'plugin', $fields ) ) { | ||||||
$registered_template = WP_Block_Templates_Registry::get_instance()->get_by_slug( $cloned_item->slug ); | ||||||
if ( $registered_template ) { | ||||||
$data['plugin'] = $registered_template->plugin; | ||||||
} | ||||||
} | ||||||
|
||||||
if ( rest_is_field_included( 'author_text', $fields ) ) { | ||||||
$data['author_text'] = $this->get_wp_templates_author_text_field( $template ); | ||||||
} | ||||||
|
||||||
if ( rest_is_field_included( 'original_source', $fields ) ) { | ||||||
$data['original_source'] = $this->get_wp_templates_original_source_field( $template ); | ||||||
} | ||||||
|
||||||
$response = rest_ensure_response( $data ); | ||||||
|
||||||
if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { | ||||||
$links = $this->prepare_links( $template->id ); | ||||||
$response->add_links( $links ); | ||||||
if ( ! empty( $links['self']['href'] ) ) { | ||||||
$actions = $this->get_available_actions(); | ||||||
$self = $links['self']['href']; | ||||||
foreach ( $actions as $rel ) { | ||||||
$response->add_link( $rel, $self ); | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
return $response; | ||||||
} | ||||||
|
||||||
/** | ||||||
* Returns the source from where the template originally comes from. | ||||||
* | ||||||
* @param WP_Block_Template $template_object Template instance. | ||||||
* @return string Original source of the template one of theme, plugin, site, or user. | ||||||
*/ | ||||||
// @core-merge: Changed the comments format (from inline to multi-line) in the entire function. | ||||||
private static function get_wp_templates_original_source_field( $template_object ) { | ||||||
Aljullu marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
if ( 'wp_template' === $template_object->type || 'wp_template_part' === $template_object->type ) { | ||||||
/* | ||||||
* Added by theme. | ||||||
* Template originally provided by a theme, but customized by a user. | ||||||
* Templates originally didn't have the 'origin' field so identify | ||||||
* older customized templates by checking for no origin and a 'theme' | ||||||
* or 'custom' source. | ||||||
*/ | ||||||
if ( $template_object->has_theme_file && | ||||||
( 'theme' === $template_object->origin || ( | ||||||
empty( $template_object->origin ) && in_array( | ||||||
$template_object->source, | ||||||
array( | ||||||
'theme', | ||||||
'custom', | ||||||
), | ||||||
true | ||||||
) ) | ||||||
) | ||||||
) { | ||||||
return 'theme'; | ||||||
} | ||||||
|
||||||
// Added by plugin. | ||||||
// @core-merge: Removed `$template_object->has_theme_file` check from this if clause. | ||||||
if ( 'plugin' === $template_object->origin ) { | ||||||
return 'plugin'; | ||||||
} | ||||||
|
||||||
/* | ||||||
* Added by site. | ||||||
* Template was created from scratch, but has no author. Author support | ||||||
* was only added to templates in WordPress 5.9. Fallback to showing the | ||||||
* site logo and title. | ||||||
*/ | ||||||
if ( empty( $template_object->has_theme_file ) && 'custom' === $template_object->source && empty( $template_object->author ) ) { | ||||||
return 'site'; | ||||||
} | ||||||
} | ||||||
|
||||||
// Added by user. | ||||||
return 'user'; | ||||||
} | ||||||
|
||||||
/** | ||||||
* Returns a human readable text for the author of the template. | ||||||
* | ||||||
* @param WP_Block_Template $template_object Template instance. | ||||||
* @return string Human readable text for the author. | ||||||
*/ | ||||||
private static function get_wp_templates_author_text_field( $template_object ) { | ||||||
$original_source = self::get_wp_templates_original_source_field( $template_object ); | ||||||
switch ( $original_source ) { | ||||||
case 'theme': | ||||||
$theme_name = wp_get_theme( $template_object->theme )->get( 'Name' ); | ||||||
return empty( $theme_name ) ? $template_object->theme : $theme_name; | ||||||
case 'plugin': | ||||||
// @core-merge: Prioritize plugin name instead of theme name for plugin-registered templates. | ||||||
if ( ! function_exists( 'get_plugins' ) || ! function_exists( 'get_plugin_data' ) ) { | ||||||
require_once ABSPATH . 'wp-admin/includes/plugin.php'; | ||||||
} | ||||||
if ( isset( $template_object->plugin ) ) { | ||||||
Aljullu marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
$plugins = wp_get_active_and_valid_plugins(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
No need to have the active and valid check. We just need to find the plugin data. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @TimothyBJacobs This was an earlier suggestion of mine. As the registered templates will be from active plugins I think it's fine to use the faster function but there's a chance I am missing something. Am I? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My thinking is I could definitely be wrong there, though. It's probably worth pulling into a method and benching it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's basically to "fall back" to the current behavior in I could refactor it to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @TimothyBJacobs is this a blocker for this PR to land? It doesn't seem a big change to commit your suggestion and in general I think we would be usually at the |
||||||
|
||||||
foreach ( $plugins as $plugin_file ) { | ||||||
$plugin_basename = plugin_basename( $plugin_file ); | ||||||
// Split basename by '/' to get the plugin slug. | ||||||
list( $plugin_slug, ) = explode( '/', $plugin_basename ); | ||||||
|
||||||
if ( $plugin_slug === $template_object->plugin ) { | ||||||
$plugin_data = get_plugin_data( $plugin_file ); | ||||||
|
||||||
if ( ! empty( $plugin_data['Name'] ) ) { | ||||||
return $plugin_data['Name']; | ||||||
} | ||||||
|
||||||
break; | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
/* | ||||||
* Fall back to the theme name if the plugin is not defined. That's needed to keep backwards | ||||||
* compatibility with templates that were registered before the plugin attribute was added. | ||||||
*/ | ||||||
$plugins = get_plugins(); | ||||||
$plugin_basename = plugin_basename( sanitize_text_field( $template_object->theme . '.php' ) ); | ||||||
if ( isset( $plugins[ $plugin_basename ] ) && isset( $plugins[ $plugin_basename ]['Name'] ) ) { | ||||||
return $plugins[ $plugin_basename ]['Name']; | ||||||
} | ||||||
return isset( $template_object->plugin ) ? | ||||||
$template_object->plugin : | ||||||
$template_object->theme; | ||||||
// @core-merge: End of changes to merge in core. | ||||||
case 'site': | ||||||
return get_bloginfo( 'name' ); | ||||||
case 'user': | ||||||
$author = get_user_by( 'id', $template_object->author ); | ||||||
if ( ! $author ) { | ||||||
return __( 'Unknown author' ); | ||||||
} | ||||||
return $author->get( 'display_name' ); | ||||||
peterwilsoncc marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
} | ||||||
} | ||||||
} |
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.
Can you clarify to me what's different in the endpoint compare trunk? It's not really clear because of how the code is extended.
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 are some
@core-merge
comments in this file (I updated them in the last commit). Every function should have a comment either at the top of the function or inline detailing the changes. Is that enough, or is there a better way to document this?