Add Site Editor and PHP changes from Gutenberg 10.1 - 11.9

- First pass at adding the site editor from the Gutenberg plugin to
  wp-admin/site-editor.php.
- Adds miscellaneous PHP changes from Gutenberg 10.1 - 11.9.

Follows [52042].
See #54337.
Props youknowriad, aristath, hellofromtonya, gziolo.


git-svn-id: https://develop.svn.wordpress.org/trunk@52069 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Robert Anderson
2021-11-09 02:15:23 +00:00
parent ecf1d6a158
commit f034bc832e
59 changed files with 4240 additions and 168 deletions
+13 -4
View File
@@ -15,29 +15,38 @@ require ABSPATH . WPINC . '/blocks/latest-comments.php';
require ABSPATH . WPINC . '/blocks/latest-posts.php';
require ABSPATH . WPINC . '/blocks/legacy-widget.php';
require ABSPATH . WPINC . '/blocks/loginout.php';
require ABSPATH . WPINC . '/blocks/navigation-area.php';
require ABSPATH . WPINC . '/blocks/navigation-link.php';
require ABSPATH . WPINC . '/blocks/navigation-submenu.php';
require ABSPATH . WPINC . '/blocks/navigation.php';
require ABSPATH . WPINC . '/blocks/page-list.php';
require ABSPATH . WPINC . '/blocks/pattern.php';
require ABSPATH . WPINC . '/blocks/post-author.php';
require ABSPATH . WPINC . '/blocks/post-comments.php';
require ABSPATH . WPINC . '/blocks/post-content.php';
require ABSPATH . WPINC . '/blocks/post-date.php';
require ABSPATH . WPINC . '/blocks/post-excerpt.php';
require ABSPATH . WPINC . '/blocks/post-featured-image.php';
require ABSPATH . WPINC . '/blocks/post-navigation-link.php';
require ABSPATH . WPINC . '/blocks/post-template.php';
require ABSPATH . WPINC . '/blocks/post-terms.php';
require ABSPATH . WPINC . '/blocks/post-title.php';
require ABSPATH . WPINC . '/blocks/post-template.php';
require ABSPATH . WPINC . '/blocks/query.php';
require ABSPATH . WPINC . '/blocks/query-pagination.php';
require ABSPATH . WPINC . '/blocks/query-pagination-next.php';
require ABSPATH . WPINC . '/blocks/query-pagination-numbers.php';
require ABSPATH . WPINC . '/blocks/query-pagination-previous.php';
require ABSPATH . WPINC . '/blocks/query-pagination.php';
require ABSPATH . WPINC . '/blocks/query-title.php';
require ABSPATH . WPINC . '/blocks/query.php';
require ABSPATH . WPINC . '/blocks/rss.php';
require ABSPATH . WPINC . '/blocks/search.php';
require ABSPATH . WPINC . '/blocks/shortcode.php';
require ABSPATH . WPINC . '/blocks/site-tagline.php';
require ABSPATH . WPINC . '/blocks/site-logo.php';
require ABSPATH . WPINC . '/blocks/site-tagline.php';
require ABSPATH . WPINC . '/blocks/site-title.php';
require ABSPATH . WPINC . '/blocks/social-link.php';
require ABSPATH . WPINC . '/blocks/tag-cloud.php';
require ABSPATH . WPINC . '/blocks/template-part.php';
require ABSPATH . WPINC . '/blocks/term-description.php';
/**
* Registers core block types using metadata files.
@@ -0,0 +1,21 @@
<?php
/**
* Server-side rendering of the `core/navigation-area` block.
*
* @package gutenberg
*/
/**
* Registers the `core/navigation-area` block on the server.
*/
function register_block_core_navigation_area() {
register_block_type_from_metadata(
__DIR__ . '/navigation-area',
array(
'provides_context' => array(
'navigationArea' => 'area',
),
)
);
}
add_action( 'init', 'register_block_core_navigation_area' );
@@ -0,0 +1,27 @@
{
"apiVersion": 2,
"name": "core/navigation-area",
"title": "Navigation Area",
"category": "theme",
"description": "Define a navigation area for your theme. The navigation block associated with this area will be automatically displayed.",
"keywords": [
"menu",
"navigation",
"links",
"location"
],
"textdomain": "default",
"attributes": {
"area": {
"type": "string",
"default": "primary"
}
},
"providesContext": {
"navigationArea": "area"
},
"supports": {
"html": false,
"inserter": true
}
}
+350
View File
@@ -0,0 +1,350 @@
<?php
/**
* Server-side rendering of the `core/navigation-link` block.
*
* @package gutenberg
*/
/**
* Build an array with CSS classes and inline styles defining the colors
* which will be applied to the navigation markup in the front-end.
*
* @param array $context Navigation block context.
* @param array $attributes Block attributes.
* @return array Colors CSS classes and inline styles.
*/
function block_core_navigation_link_build_css_colors( $context, $attributes ) {
$colors = array(
'css_classes' => array(),
'inline_styles' => '',
);
$is_sub_menu = isset( $attributes['isTopLevelLink'] ) ? ( ! $attributes['isTopLevelLink'] ) : false;
// Text color.
$named_text_color = null;
$custom_text_color = null;
if ( $is_sub_menu && array_key_exists( 'customOverlayTextColor', $context ) ) {
$custom_text_color = $context['customOverlayTextColor'];
} elseif ( $is_sub_menu && array_key_exists( 'overlayTextColor', $context ) ) {
$named_text_color = $context['overlayTextColor'];
} elseif ( array_key_exists( 'customTextColor', $context ) ) {
$custom_text_color = $context['customTextColor'];
} elseif ( array_key_exists( 'textColor', $context ) ) {
$named_text_color = $context['textColor'];
} elseif ( isset( $context['style']['color']['text'] ) ) {
$custom_text_color = $context['style']['color']['text'];
}
// If has text color.
if ( ! is_null( $named_text_color ) ) {
// Add the color class.
array_push( $colors['css_classes'], 'has-text-color', sprintf( 'has-%s-color', $named_text_color ) );
} elseif ( ! is_null( $custom_text_color ) ) {
// Add the custom color inline style.
$colors['css_classes'][] = 'has-text-color';
$colors['inline_styles'] .= sprintf( 'color: %s;', $custom_text_color );
}
// Background color.
$named_background_color = null;
$custom_background_color = null;
if ( $is_sub_menu && array_key_exists( 'customOverlayBackgroundColor', $context ) ) {
$custom_background_color = $context['customOverlayBackgroundColor'];
} elseif ( $is_sub_menu && array_key_exists( 'overlayBackgroundColor', $context ) ) {
$named_background_color = $context['overlayBackgroundColor'];
} elseif ( array_key_exists( 'customBackgroundColor', $context ) ) {
$custom_background_color = $context['customBackgroundColor'];
} elseif ( array_key_exists( 'backgroundColor', $context ) ) {
$named_background_color = $context['backgroundColor'];
} elseif ( isset( $context['style']['color']['background'] ) ) {
$custom_background_color = $context['style']['color']['background'];
}
// If has background color.
if ( ! is_null( $named_background_color ) ) {
// Add the background-color class.
array_push( $colors['css_classes'], 'has-background', sprintf( 'has-%s-background-color', $named_background_color ) );
} elseif ( ! is_null( $custom_background_color ) ) {
// Add the custom background-color inline style.
$colors['css_classes'][] = 'has-background';
$colors['inline_styles'] .= sprintf( 'background-color: %s;', $custom_background_color );
}
return $colors;
}
/**
* Build an array with CSS classes and inline styles defining the font sizes
* which will be applied to the navigation markup in the front-end.
*
* @param array $context Navigation block context.
* @return array Font size CSS classes and inline styles.
*/
function block_core_navigation_link_build_css_font_sizes( $context ) {
// CSS classes.
$font_sizes = array(
'css_classes' => array(),
'inline_styles' => '',
);
$has_named_font_size = array_key_exists( 'fontSize', $context );
$has_custom_font_size = isset( $context['style']['typography']['fontSize'] );
if ( $has_named_font_size ) {
// Add the font size class.
$font_sizes['css_classes'][] = sprintf( 'has-%s-font-size', $context['fontSize'] );
} elseif ( $has_custom_font_size ) {
// Add the custom font size inline style.
$font_sizes['inline_styles'] = sprintf( 'font-size: %spx;', $context['style']['typography']['fontSize'] );
}
return $font_sizes;
}
/**
* Returns the top-level submenu SVG chevron icon.
*
* @return string
*/
function block_core_navigation_link_render_submenu_icon() {
return '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none" role="img" aria-hidden="true" focusable="false"><path d="M1.50002 4L6.00002 8L10.5 4" stroke-width="1.5"></path></svg>';
}
/**
* Renders the `core/navigation-link` block.
*
* @param array $attributes The block attributes.
* @param array $content The saved content.
* @param array $block The parsed block.
*
* @return string Returns the post content with the legacy widget added.
*/
function render_block_core_navigation_link( $attributes, $content, $block ) {
$navigation_link_has_id = isset( $attributes['id'] ) && is_numeric( $attributes['id'] );
$is_post_type = isset( $attributes['kind'] ) && 'post-type' === $attributes['kind'];
$is_post_type = $is_post_type || isset( $attributes['type'] ) && ( 'post' === $attributes['type'] || 'page' === $attributes['type'] );
// Don't render the block's subtree if it is a draft or if the ID does not exist.
if ( $is_post_type && $navigation_link_has_id ) {
$post = get_post( $attributes['id'] );
if ( ! $post || 'publish' !== $post->post_status ) {
return '';
}
}
// Don't render the block's subtree if it has no label.
if ( empty( $attributes['label'] ) ) {
return '';
}
$colors = block_core_navigation_link_build_css_colors( $block->context, $attributes );
$font_sizes = block_core_navigation_link_build_css_font_sizes( $block->context );
$classes = array_merge(
$colors['css_classes'],
$font_sizes['css_classes']
);
$style_attribute = ( $colors['inline_styles'] . $font_sizes['inline_styles'] );
$css_classes = trim( implode( ' ', $classes ) );
$has_submenu = count( $block->inner_blocks ) > 0;
$is_active = ! empty( $attributes['id'] ) && ( get_the_ID() === $attributes['id'] );
$wrapper_attributes = get_block_wrapper_attributes(
array(
'class' => $css_classes . ' wp-block-navigation-item' . ( $has_submenu ? ' has-child' : '' ) .
( $is_active ? ' current-menu-item' : '' ),
'style' => $style_attribute,
)
);
$html = '<li ' . $wrapper_attributes . '>' .
'<a class="wp-block-navigation-item__content" ';
// Start appending HTML attributes to anchor tag.
if ( isset( $attributes['url'] ) ) {
$html .= ' href="' . esc_url( $attributes['url'] ) . '"';
}
if ( $is_active ) {
$html .= ' aria-current="page"';
}
if ( isset( $attributes['opensInNewTab'] ) && true === $attributes['opensInNewTab'] ) {
$html .= ' target="_blank" ';
}
if ( isset( $attributes['rel'] ) ) {
$html .= ' rel="' . esc_attr( $attributes['rel'] ) . '"';
} elseif ( isset( $attributes['nofollow'] ) && $attributes['nofollow'] ) {
$html .= ' rel="nofollow"';
}
if ( isset( $attributes['title'] ) ) {
$html .= ' title="' . esc_attr( $attributes['title'] ) . '"';
}
// End appending HTML attributes to anchor tag.
// Start anchor tag content.
$html .= '>' .
// Wrap title with span to isolate it from submenu icon.
'<span class="wp-block-navigation-item__label">';
if ( isset( $attributes['label'] ) ) {
$html .= wp_kses(
$attributes['label'],
array(
'code' => array(),
'em' => array(),
'img' => array(
'scale' => array(),
'class' => array(),
'style' => array(),
'src' => array(),
'alt' => array(),
),
's' => array(),
'span' => array(
'style' => array(),
),
'strong' => array(),
)
);
}
$html .= '</span>';
if ( isset( $block->context['showSubmenuIcon'] ) && $block->context['showSubmenuIcon'] && $has_submenu ) {
// The submenu icon can be hidden by a CSS rule on the Navigation Block.
$html .= '<span class="wp-block-navigation__submenu-icon">' . block_core_navigation_link_render_submenu_icon() . '</span>';
}
$html .= '</a>';
// End anchor tag content.
if ( $has_submenu ) {
$inner_blocks_html = '';
foreach ( $block->inner_blocks as $inner_block ) {
$inner_blocks_html .= $inner_block->render();
}
$html .= sprintf(
'<ul class="wp-block-navigation__submenu-container">%s</ul>',
$inner_blocks_html
);
}
$html .= '</li>';
return $html;
}
/**
* Returns a navigation link variation
*
* @param WP_Taxonomy|WP_Post_Type $entity post type or taxonomy entity.
* @param string $kind string of value 'taxonomy' or 'post-type'.
*
* @return array
*/
function build_variation_for_navigation_link( $entity, $kind ) {
$title = '';
$description = '';
if ( property_exists( $entity->labels, 'item_link' ) ) {
$title = $entity->labels->item_link;
}
if ( property_exists( $entity->labels, 'item_link_description' ) ) {
$description = $entity->labels->item_link_description;
}
$variation = array(
'name' => $entity->name,
'title' => $title,
'description' => $description,
'attributes' => array(
'type' => $entity->name,
'kind' => $kind,
),
);
// Tweak some value for the variations.
$variation_overrides = array(
'post_tag' => array(
'name' => 'tag',
'attributes' => array(
'type' => 'tag',
'kind' => $kind,
),
),
'post_format' => array(
// The item_link and item_link_description for post formats is the
// same as for tags, so need to be overridden.
'title' => __( 'Post Format Link' ),
'description' => __( 'A link to a post format' ),
'attributes' => array(
'type' => 'post_format',
'kind' => $kind,
),
),
);
if ( array_key_exists( $entity->name, $variation_overrides ) ) {
$variation = array_merge(
$variation,
$variation_overrides[ $entity->name ]
);
}
return $variation;
}
/**
* Register the navigation link block.
*
* @uses render_block_core_navigation()
* @throws WP_Error An WP_Error exception parsing the block definition.
*/
function register_block_core_navigation_link() {
$post_types = get_post_types( array( 'show_in_nav_menus' => true ), 'objects' );
$taxonomies = get_taxonomies( array( 'show_in_nav_menus' => true ), 'objects' );
// Use two separate arrays as a way to order the variations in the UI.
// Known variations (like Post Link and Page Link) are added to the
// `built_ins` array. Variations for custom post types and taxonomies are
// added to the `variations` array and will always appear after `built-ins.
$built_ins = array();
$variations = array();
if ( $post_types ) {
foreach ( $post_types as $post_type ) {
$variation = build_variation_for_navigation_link( $post_type, 'post-type' );
if ( $post_type->_builtin ) {
$built_ins[] = $variation;
} else {
$variations[] = $variation;
}
}
}
if ( $taxonomies ) {
foreach ( $taxonomies as $taxonomy ) {
$variation = build_variation_for_navigation_link( $taxonomy, 'taxonomy' );
if ( $taxonomy->_builtin ) {
$built_ins[] = $variation;
} else {
$variations[] = $variation;
}
}
}
register_block_type_from_metadata(
__DIR__ . '/navigation-link',
array(
'render_callback' => 'render_block_core_navigation_link',
'variations' => array_merge( $built_ins, $variations ),
)
);
}
add_action( 'init', 'register_block_core_navigation_link' );
@@ -0,0 +1,65 @@
{
"apiVersion": 2,
"name": "core/navigation-link",
"title": "Custom Link",
"category": "design",
"parent": [
"core/navigation"
],
"description": "Add a page, link, or another item to your navigation.",
"textdomain": "default",
"attributes": {
"label": {
"type": "string"
},
"type": {
"type": "string"
},
"description": {
"type": "string"
},
"rel": {
"type": "string"
},
"id": {
"type": "number"
},
"opensInNewTab": {
"type": "boolean",
"default": false
},
"url": {
"type": "string"
},
"title": {
"type": "string"
},
"kind": {
"type": "string"
},
"isTopLevelLink": {
"type": "boolean"
}
},
"usesContext": [
"textColor",
"customTextColor",
"backgroundColor",
"customBackgroundColor",
"overlayTextColor",
"customOverlayTextColor",
"overlayBackgroundColor",
"customOverlayBackgroundColor",
"fontSize",
"customFontSize",
"showSubmenuIcon",
"style"
],
"supports": {
"reusable": false,
"html": false,
"__experimentalSlashInserter": true
},
"editorStyle": "wp-block-navigation-link-editor",
"style": "wp-block-navigation-link"
}
@@ -0,0 +1,300 @@
<?php
/**
* Server-side rendering of the `core/navigation-submenu` block.
*
* @package gutenberg
*/
/**
* Build an array with CSS classes and inline styles defining the colors
* which will be applied to the navigation markup in the front-end.
*
* @param array $context Navigation block context.
* @param array $attributes Block attributes.
* @return array Colors CSS classes and inline styles.
*/
function block_core_navigation_submenu_build_css_colors( $context, $attributes ) {
$colors = array(
'css_classes' => array(),
'inline_styles' => '',
);
$is_sub_menu = isset( $attributes['isTopLevelLink'] ) ? ( ! $attributes['isTopLevelLink'] ) : false;
// Text color.
$named_text_color = null;
$custom_text_color = null;
if ( $is_sub_menu && array_key_exists( 'customOverlayTextColor', $context ) ) {
$custom_text_color = $context['customOverlayTextColor'];
} elseif ( $is_sub_menu && array_key_exists( 'overlayTextColor', $context ) ) {
$named_text_color = $context['overlayTextColor'];
} elseif ( array_key_exists( 'customTextColor', $context ) ) {
$custom_text_color = $context['customTextColor'];
} elseif ( array_key_exists( 'textColor', $context ) ) {
$named_text_color = $context['textColor'];
} elseif ( isset( $context['style']['color']['text'] ) ) {
$custom_text_color = $context['style']['color']['text'];
}
// If has text color.
if ( ! is_null( $named_text_color ) ) {
// Add the color class.
array_push( $colors['css_classes'], 'has-text-color', sprintf( 'has-%s-color', $named_text_color ) );
} elseif ( ! is_null( $custom_text_color ) ) {
// Add the custom color inline style.
$colors['css_classes'][] = 'has-text-color';
$colors['inline_styles'] .= sprintf( 'color: %s;', $custom_text_color );
}
// Background color.
$named_background_color = null;
$custom_background_color = null;
if ( $is_sub_menu && array_key_exists( 'customOverlayBackgroundColor', $context ) ) {
$custom_background_color = $context['customOverlayBackgroundColor'];
} elseif ( $is_sub_menu && array_key_exists( 'overlayBackgroundColor', $context ) ) {
$named_background_color = $context['overlayBackgroundColor'];
} elseif ( array_key_exists( 'customBackgroundColor', $context ) ) {
$custom_background_color = $context['customBackgroundColor'];
} elseif ( array_key_exists( 'backgroundColor', $context ) ) {
$named_background_color = $context['backgroundColor'];
} elseif ( isset( $context['style']['color']['background'] ) ) {
$custom_background_color = $context['style']['color']['background'];
}
// If has background color.
if ( ! is_null( $named_background_color ) ) {
// Add the background-color class.
array_push( $colors['css_classes'], 'has-background', sprintf( 'has-%s-background-color', $named_background_color ) );
} elseif ( ! is_null( $custom_background_color ) ) {
// Add the custom background-color inline style.
$colors['css_classes'][] = 'has-background';
$colors['inline_styles'] .= sprintf( 'background-color: %s;', $custom_background_color );
}
return $colors;
}
/**
* Build an array with CSS classes and inline styles defining the font sizes
* which will be applied to the navigation markup in the front-end.
*
* @param array $context Navigation block context.
* @return array Font size CSS classes and inline styles.
*/
function block_core_navigation_submenu_build_css_font_sizes( $context ) {
// CSS classes.
$font_sizes = array(
'css_classes' => array(),
'inline_styles' => '',
);
$has_named_font_size = array_key_exists( 'fontSize', $context );
$has_custom_font_size = isset( $context['style']['typography']['fontSize'] );
if ( $has_named_font_size ) {
// Add the font size class.
$font_sizes['css_classes'][] = sprintf( 'has-%s-font-size', $context['fontSize'] );
} elseif ( $has_custom_font_size ) {
// Add the custom font size inline style.
$font_sizes['inline_styles'] = sprintf( 'font-size: %spx;', $context['style']['typography']['fontSize'] );
}
return $font_sizes;
}
/**
* Returns the top-level submenu SVG chevron icon.
*
* @return string
*/
function block_core_navigation_submenu_render_submenu_icon() {
return '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none" role="img" aria-hidden="true" focusable="false"><path d="M1.50002 4L6.00002 8L10.5 4" stroke-width="1.5"></path></svg>';
}
/**
* Renders the `core/navigation-submenu` block.
*
* @param array $attributes The block attributes.
* @param string $content The saved content.
* @param object $block The parsed block.
*
* @return string Returns the post content with the legacy widget added.
*/
function render_block_core_navigation_submenu( $attributes, $content, $block ) {
$navigation_link_has_id = isset( $attributes['id'] ) && is_numeric( $attributes['id'] );
$is_post_type = isset( $attributes['kind'] ) && 'post-type' === $attributes['kind'];
$is_post_type = $is_post_type || isset( $attributes['type'] ) && ( 'post' === $attributes['type'] || 'page' === $attributes['type'] );
// Don't render the block's subtree if it is a draft.
if ( $is_post_type && $navigation_link_has_id && 'publish' !== get_post_status( $attributes['id'] ) ) {
return '';
}
// Don't render the block's subtree if it has no label.
if ( empty( $attributes['label'] ) ) {
return '';
}
$colors = block_core_navigation_submenu_build_css_colors( $block->context, $attributes );
$font_sizes = block_core_navigation_submenu_build_css_font_sizes( $block->context );
$classes = array_merge(
$colors['css_classes'],
$font_sizes['css_classes']
);
$style_attribute = ( $colors['inline_styles'] . $font_sizes['inline_styles'] );
$css_classes = trim( implode( ' ', $classes ) );
$has_submenu = count( $block->inner_blocks ) > 0;
$is_active = ! empty( $attributes['id'] ) && ( get_the_ID() === $attributes['id'] );
$class_name = ! empty( $attributes['className'] ) ? implode( ' ', (array) $attributes['className'] ) : false;
if ( false !== $class_name ) {
$css_classes .= ' ' . $class_name;
}
$show_submenu_indicators = isset( $block->context['showSubmenuIcon'] ) && $block->context['showSubmenuIcon'];
$open_on_click = isset( $block->context['openSubmenusOnClick'] ) && $block->context['openSubmenusOnClick'];
$open_on_hover_and_click = isset( $block->context['openSubmenusOnClick'] ) && ! $block->context['openSubmenusOnClick'] &&
$show_submenu_indicators;
$wrapper_attributes = get_block_wrapper_attributes(
array(
'class' => $css_classes . ' wp-block-navigation-item' . ( $has_submenu ? ' has-child' : '' ) .
( $open_on_click ? ' open-on-click' : '' ) . ( $open_on_hover_and_click ? ' open-on-hover-click' : '' ) .
( $is_active ? ' current-menu-item' : '' ),
'style' => $style_attribute,
)
);
$html = '<li ' . $wrapper_attributes . '>';
// If Submenus open on hover, we render an anchor tag with attributes.
// If submenu icons are set to show, we also render a submenu button, so the submenu can be opened on click.
if ( ! $open_on_click ) {
$item_url = isset( $attributes['url'] ) ? esc_url( $attributes['url'] ) : '';
// Start appending HTML attributes to anchor tag.
$html .= '<a class="wp-block-navigation-item__content" href="' . $item_url . '"';
if ( $is_active ) {
$html .= ' aria-current="page"';
}
if ( isset( $attributes['opensInNewTab'] ) && true === $attributes['opensInNewTab'] ) {
$html .= ' target="_blank" ';
}
if ( isset( $attributes['rel'] ) ) {
$html .= ' rel="' . esc_attr( $attributes['rel'] ) . '"';
} elseif ( isset( $attributes['nofollow'] ) && $attributes['nofollow'] ) {
$html .= ' rel="nofollow"';
}
if ( isset( $attributes['title'] ) ) {
$html .= ' title="' . esc_attr( $attributes['title'] ) . '"';
}
$html .= '>';
// End appending HTML attributes to anchor tag.
if ( isset( $attributes['label'] ) ) {
$html .= wp_kses(
$attributes['label'],
array(
'code' => array(),
'em' => array(),
'img' => array(
'scale' => array(),
'class' => array(),
'style' => array(),
'src' => array(),
'alt' => array(),
),
's' => array(),
'span' => array(
'style' => array(),
),
'strong' => array(),
)
);
}
$html .= '</a>';
// End anchor tag content.
if ( $show_submenu_indicators ) {
// The submenu icon is rendered in a button here
// so that there's a clickable elment to open the submenu.
$html .= '<button class="wp-block-navigation__submenu-icon wp-block-navigation-submenu__toggle" aria-expanded="false">' . block_core_navigation_submenu_render_submenu_icon() . '</button>';
}
} else {
// If menus open on click, we render the parent as a button.
$html .= '<button class="wp-block-navigation-item__content wp-block-navigation-submenu__toggle" aria-expanded="false">';
// Wrap title with span to isolate it from submenu icon.
$html .= '<span class="wp-block-navigation-item__label">';
if ( isset( $attributes['label'] ) ) {
$html .= wp_kses(
$attributes['label'],
array(
'code' => array(),
'em' => array(),
'img' => array(
'scale' => array(),
'class' => array(),
'style' => array(),
'src' => array(),
'alt' => array(),
),
's' => array(),
'span' => array(
'style' => array(),
),
'strong' => array(),
)
);
}
$html .= '</span>';
$html .= '<span class="wp-block-navigation__submenu-icon">' . block_core_navigation_submenu_render_submenu_icon() . '</span>';
$html .= '</button>';
}
if ( $has_submenu ) {
$inner_blocks_html = '';
foreach ( $block->inner_blocks as $inner_block ) {
$inner_blocks_html .= $inner_block->render();
}
$html .= sprintf(
'<ul class="wp-block-navigation__submenu-container">%s</ul>',
$inner_blocks_html
);
}
$html .= '</li>';
return $html;
}
/**
* Register the navigation submenu block.
*
* @uses render_block_core_navigation_submenu()
* @throws WP_Error An WP_Error exception parsing the block definition.
*/
function register_block_core_navigation_submenu() {
register_block_type_from_metadata(
__DIR__ . '/navigation-submenu',
array(
'render_callback' => 'render_block_core_navigation_submenu',
)
);
}
add_action( 'init', 'register_block_core_navigation_submenu' );
@@ -0,0 +1,65 @@
{
"apiVersion": 2,
"name": "core/navigation-submenu",
"title": "Submenu",
"category": "design",
"parent": [
"core/navigation"
],
"description": "Add a submenu to your navigation.",
"textdomain": "default",
"attributes": {
"label": {
"type": "string"
},
"type": {
"type": "string"
},
"description": {
"type": "string"
},
"rel": {
"type": "string"
},
"id": {
"type": "number"
},
"opensInNewTab": {
"type": "boolean",
"default": false
},
"url": {
"type": "string"
},
"title": {
"type": "string"
},
"kind": {
"type": "string"
},
"isTopLevelItem": {
"type": "boolean"
}
},
"usesContext": [
"textColor",
"customTextColor",
"backgroundColor",
"customBackgroundColor",
"overlayTextColor",
"customOverlayTextColor",
"overlayBackgroundColor",
"customOverlayBackgroundColor",
"fontSize",
"customFontSize",
"showSubmenuIcon",
"openSubmenusOnClick",
"style"
],
"supports": {
"reusable": false,
"html": false
},
"editorStyle": "wp-block-navigation-submenu-editor",
"style": "wp-block-navigation-submenu"
}
+429
View File
@@ -0,0 +1,429 @@
<?php
/**
* Server-side rendering of the `core/navigation` block.
*
* @package gutenberg
*/
/**
* Build an array with CSS classes and inline styles defining the colors
* which will be applied to the navigation markup in the front-end.
*
* @param array $attributes Navigation block attributes.
* @return array Colors CSS classes and inline styles.
*/
function block_core_navigation_build_css_colors( $attributes ) {
$colors = array(
'css_classes' => array(),
'inline_styles' => '',
);
// Text color.
$has_named_text_color = array_key_exists( 'textColor', $attributes );
$has_custom_text_color = array_key_exists( 'customTextColor', $attributes );
// If has text color.
if ( $has_custom_text_color || $has_named_text_color ) {
// Add has-text-color class.
$colors['css_classes'][] = 'has-text-color';
}
if ( $has_named_text_color ) {
// Add the color class.
$colors['css_classes'][] = sprintf( 'has-%s-color', $attributes['textColor'] );
} elseif ( $has_custom_text_color ) {
// Add the custom color inline style.
$colors['inline_styles'] .= sprintf( 'color: %s;', $attributes['customTextColor'] );
}
// Background color.
$has_named_background_color = array_key_exists( 'backgroundColor', $attributes );
$has_custom_background_color = array_key_exists( 'customBackgroundColor', $attributes );
// If has background color.
if ( $has_custom_background_color || $has_named_background_color ) {
// Add has-background class.
$colors['css_classes'][] = 'has-background';
}
if ( $has_named_background_color ) {
// Add the background-color class.
$colors['css_classes'][] = sprintf( 'has-%s-background-color', $attributes['backgroundColor'] );
} elseif ( $has_custom_background_color ) {
// Add the custom background-color inline style.
$colors['inline_styles'] .= sprintf( 'background-color: %s;', $attributes['customBackgroundColor'] );
}
return $colors;
}
/**
* Build an array with CSS classes and inline styles defining the font sizes
* which will be applied to the navigation markup in the front-end.
*
* @param array $attributes Navigation block attributes.
* @return array Font size CSS classes and inline styles.
*/
function block_core_navigation_build_css_font_sizes( $attributes ) {
// CSS classes.
$font_sizes = array(
'css_classes' => array(),
'inline_styles' => '',
);
$has_named_font_size = array_key_exists( 'fontSize', $attributes );
$has_custom_font_size = array_key_exists( 'customFontSize', $attributes );
if ( $has_named_font_size ) {
// Add the font size class.
$font_sizes['css_classes'][] = sprintf( 'has-%s-font-size', $attributes['fontSize'] );
} elseif ( $has_custom_font_size ) {
// Add the custom font size inline style.
$font_sizes['inline_styles'] = sprintf( 'font-size: %spx;', $attributes['customFontSize'] );
}
return $font_sizes;
}
/**
* Returns the menu items for a WordPress menu location.
*
* @param string $location The menu location.
* @return array Menu items for the location.
*/
function gutenberg_get_menu_items_at_location( $location ) {
if ( empty( $location ) ) {
return;
}
// Build menu data. The following approximates the code in
// `wp_nav_menu()` and `gutenberg_output_block_nav_menu`.
// Find the location in the list of locations, returning early if the
// location can't be found.
$locations = get_nav_menu_locations();
if ( ! isset( $locations[ $location ] ) ) {
return;
}
// Get the menu from the location, returning early if there is no
// menu or there was an error.
$menu = wp_get_nav_menu_object( $locations[ $location ] );
if ( ! $menu || is_wp_error( $menu ) ) {
return;
}
$menu_items = wp_get_nav_menu_items( $menu->term_id, array( 'update_post_term_cache' => false ) );
_wp_menu_item_classes_by_context( $menu_items );
return $menu_items;
}
/**
* Sorts a standard array of menu items into a nested structure keyed by the
* id of the parent menu.
*
* @param array $menu_items Menu items to sort.
* @return array An array keyed by the id of the parent menu where each element
* is an array of menu items that belong to that parent.
*/
function gutenberg_sort_menu_items_by_parent_id( $menu_items ) {
$sorted_menu_items = array();
foreach ( (array) $menu_items as $menu_item ) {
$sorted_menu_items[ $menu_item->menu_order ] = $menu_item;
}
unset( $menu_items, $menu_item );
$menu_items_by_parent_id = array();
foreach ( $sorted_menu_items as $menu_item ) {
$menu_items_by_parent_id[ $menu_item->menu_item_parent ][] = $menu_item;
}
return $menu_items_by_parent_id;
}
/**
* Turns menu item data into a nested array of parsed blocks
*
* @param array $menu_items An array of menu items that represent
* an individual level of a menu.
* @param array $menu_items_by_parent_id An array keyed by the id of the
* parent menu where each element is an
* array of menu items that belong to
* that parent.
* @return array An array of parsed block data.
*/
function gutenberg_parse_blocks_from_menu_items( $menu_items, $menu_items_by_parent_id ) {
if ( empty( $menu_items ) ) {
return array();
}
$blocks = array();
foreach ( $menu_items as $menu_item ) {
$class_name = ! empty( $menu_item->classes ) ? implode( ' ', (array) $menu_item->classes ) : null;
$id = ( null !== $menu_item->object_id && 'custom' !== $menu_item->object ) ? $menu_item->object_id : null;
$opens_in_new_tab = null !== $menu_item->target && '_blank' === $menu_item->target;
$rel = ( null !== $menu_item->xfn && '' !== $menu_item->xfn ) ? $menu_item->xfn : null;
$kind = null !== $menu_item->type ? str_replace( '_', '-', $menu_item->type ) : 'custom';
$block = array(
'blockName' => 'core/navigation-link',
'attrs' => array(
'className' => $class_name,
'description' => $menu_item->description,
'id' => $id,
'kind' => $kind,
'label' => $menu_item->title,
'opensInNewTab' => $opens_in_new_tab,
'rel' => $rel,
'title' => $menu_item->attr_title,
'type' => $menu_item->object,
'url' => $menu_item->url,
),
);
$block['innerBlocks'] = gutenberg_parse_blocks_from_menu_items(
isset( $menu_items_by_parent_id[ $menu_item->ID ] )
? $menu_items_by_parent_id[ $menu_item->ID ]
: array(),
$menu_items_by_parent_id
);
$blocks[] = $block;
}
return $blocks;
}
/**
* Returns the top-level submenu SVG chevron icon.
*
* @return string
*/
function block_core_navigation_render_submenu_icon() {
return '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none" role="img" aria-hidden="true" focusable="false"><path d="M1.50002 4L6.00002 8L10.5 4" stroke-width="1.5"></path></svg>';
}
/**
* Renders the `core/navigation` block on server.
*
* @param array $attributes The block attributes.
* @param array $content The saved content.
* @param array $block The parsed block.
*
* @return string Returns the post content with the legacy widget added.
*/
function render_block_core_navigation( $attributes, $content, $block ) {
/**
* Deprecated:
* The rgbTextColor and rgbBackgroundColor attributes
* have been deprecated in favor of
* customTextColor and customBackgroundColor ones.
* Move the values from old attrs to the new ones.
*/
if ( isset( $attributes['rgbTextColor'] ) && empty( $attributes['textColor'] ) ) {
$attributes['customTextColor'] = $attributes['rgbTextColor'];
}
if ( isset( $attributes['rgbBackgroundColor'] ) && empty( $attributes['backgroundColor'] ) ) {
$attributes['customBackgroundColor'] = $attributes['rgbBackgroundColor'];
}
unset( $attributes['rgbTextColor'], $attributes['rgbBackgroundColor'] );
/**
* This is for backwards compatibility after `isResponsive` attribute has been removed.
*/
$has_old_responsive_attribute = ! empty( $attributes['isResponsive'] ) && $attributes['isResponsive'];
$is_responsive_menu = isset( $attributes['overlayMenu'] ) && 'never' !== $attributes['overlayMenu'] || $has_old_responsive_attribute;
$should_load_view_script = ! wp_script_is( 'wp-block-navigation-view' ) && ( $is_responsive_menu || $attributes['openSubmenusOnClick'] || $attributes['showSubmenuIcon'] );
if ( $should_load_view_script ) {
wp_enqueue_script( 'wp-block-navigation-view' );
}
$inner_blocks = $block->inner_blocks;
// If `__unstableLocation` is defined, create inner blocks from the classic menu assigned to that location.
if ( empty( $inner_blocks ) && array_key_exists( '__unstableLocation', $attributes ) ) {
$menu_items = gutenberg_get_menu_items_at_location( $attributes['__unstableLocation'] );
if ( empty( $menu_items ) ) {
return '';
}
$menu_items_by_parent_id = gutenberg_sort_menu_items_by_parent_id( $menu_items );
$parsed_blocks = gutenberg_parse_blocks_from_menu_items( $menu_items_by_parent_id[0], $menu_items_by_parent_id );
$inner_blocks = new WP_Block_List( $parsed_blocks, $attributes );
}
if ( ! empty( $block->context['navigationArea'] ) ) {
$area = $block->context['navigationArea'];
$mapping = get_option( 'fse_navigation_areas', array() );
if ( ! empty( $mapping[ $area ] ) ) {
$attributes['navigationMenuId'] = $mapping[ $area ];
}
}
// Load inner blocks from the navigation post.
if ( array_key_exists( 'navigationMenuId', $attributes ) ) {
$navigation_post = get_post( $attributes['navigationMenuId'] );
if ( ! isset( $navigation_post ) ) {
return '';
}
$parsed_blocks = parse_blocks( $navigation_post->post_content );
// 'parse_blocks' includes a null block with '\n\n' as the content when
// it encounters whitespace. This code strips it.
$compacted_blocks = array_filter(
$parsed_blocks,
function( $block ) {
return isset( $block['blockName'] );
}
);
// TODO - this uses the full navigation block attributes for the
// context which could be refined.
$inner_blocks = new WP_Block_List( $compacted_blocks, $attributes );
}
if ( empty( $inner_blocks ) ) {
return '';
}
$colors = block_core_navigation_build_css_colors( $attributes );
$font_sizes = block_core_navigation_build_css_font_sizes( $attributes );
$classes = array_merge(
$colors['css_classes'],
$font_sizes['css_classes'],
$is_responsive_menu ? array( 'is-responsive' ) : array()
);
$inner_blocks_html = '';
$is_list_open = false;
foreach ( $inner_blocks as $inner_block ) {
if ( ( 'core/navigation-link' === $inner_block->name || 'core/home-link' === $inner_block->name || 'core/site-title' === $inner_block->name || 'core/site-logo' === $inner_block->name || 'core/navigation-submenu' === $inner_block->name ) && ! $is_list_open ) {
$is_list_open = true;
$inner_blocks_html .= '<ul class="wp-block-navigation__container">';
}
if ( 'core/navigation-link' !== $inner_block->name && 'core/home-link' !== $inner_block->name && 'core/site-title' !== $inner_block->name && 'core/site-logo' !== $inner_block->name && 'core/navigation-submenu' !== $inner_block->name && $is_list_open ) {
$is_list_open = false;
$inner_blocks_html .= '</ul>';
}
if ( 'core/site-title' === $inner_block->name || 'core/site-logo' === $inner_block->name ) {
$inner_blocks_html .= '<li class="wp-block-navigation-item">' . $inner_block->render() . '</li>';
} else {
$inner_blocks_html .= $inner_block->render();
}
}
if ( $is_list_open ) {
$inner_blocks_html .= '</ul>';
}
$block_styles = isset( $attributes['styles'] ) ? $attributes['styles'] : '';
$wrapper_attributes = get_block_wrapper_attributes(
array(
'class' => implode( ' ', $classes ),
'style' => $block_styles . $colors['inline_styles'] . $font_sizes['inline_styles'],
)
);
$modal_unique_id = uniqid();
// Determine whether or not navigation elements should be wrapped in the markup required to make it responsive,
// return early if they don't.
if ( ! $is_responsive_menu ) {
return sprintf(
'<nav %1$s>%2$s</nav>',
$wrapper_attributes,
$inner_blocks_html
);
}
$is_hidden_by_default = isset( $attributes['overlayMenu'] ) && 'always' === $attributes['overlayMenu'];
$responsive_container_classes = array(
'wp-block-navigation__responsive-container',
$is_hidden_by_default ? 'hidden-by-default' : '',
);
$open_button_classes = array(
'wp-block-navigation__responsive-container-open',
$is_hidden_by_default ? 'always-shown' : '',
);
$responsive_container_markup = sprintf(
'<button aria-expanded="false" aria-haspopup="true" aria-label="%3$s" class="%6$s" data-micromodal-trigger="modal-%1$s"><svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img" aria-hidden="true" focusable="false"><rect x="4" y="7.5" width="16" height="1.5" /><rect x="4" y="15" width="16" height="1.5" /></svg></button>
<div class="%5$s" id="modal-%1$s" aria-hidden="true">
<div class="wp-block-navigation__responsive-close" tabindex="-1" data-micromodal-close>
<div class="wp-block-navigation__responsive-dialog" role="dialog" aria-modal="true" aria-labelledby="modal-%1$s-title" >
<button aria-label="%4$s" data-micromodal-close class="wp-block-navigation__responsive-container-close"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" role="img" aria-hidden="true" focusable="false"><path d="M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z"></path></svg></button>
<div class="wp-block-navigation__responsive-container-content" id="modal-%1$s-content">
%2$s
</div>
</div>
</div>
</div>',
$modal_unique_id,
$inner_blocks_html,
__( 'Open menu' ), // Open button label.
__( 'Close menu' ), // Close button label.
implode( ' ', $responsive_container_classes ),
implode( ' ', $open_button_classes )
);
return sprintf(
'<nav %1$s>%2$s</nav>',
$wrapper_attributes,
$responsive_container_markup
);
}
/**
* Register the navigation block.
*
* @uses render_block_core_navigation()
* @throws WP_Error An WP_Error exception parsing the block definition.
*/
function register_block_core_navigation() {
register_block_type_from_metadata(
__DIR__ . '/navigation',
array(
'render_callback' => 'render_block_core_navigation',
)
);
}
add_action( 'init', 'register_block_core_navigation' );
/**
* Filter that changes the parsed attribute values of navigation blocks contain typographic presets to contain the values directly.
*
* @param array $parsed_block The block being rendered.
* @return array The block being rendered without typographic presets.
*/
function block_core_navigation_typographic_presets_backcompatibility( $parsed_block ) {
if ( 'core/navigation' === $parsed_block['blockName'] ) {
$attribute_to_prefix_map = array(
'fontStyle' => 'var:preset|font-style|',
'fontWeight' => 'var:preset|font-weight|',
'textDecoration' => 'var:preset|text-decoration|',
'textTransform' => 'var:preset|text-transform|',
);
foreach ( $attribute_to_prefix_map as $style_attribute => $prefix ) {
if ( ! empty( $parsed_block['attrs']['style']['typography'][ $style_attribute ] ) ) {
$prefix_len = strlen( $prefix );
$attribute_value = &$parsed_block['attrs']['style']['typography'][ $style_attribute ];
if ( 0 === strncmp( $attribute_value, $prefix, $prefix_len ) ) {
$attribute_value = substr( $attribute_value, $prefix_len );
}
if ( 'textDecoration' === $style_attribute && 'strikethrough' === $attribute_value ) {
$attribute_value = 'line-through';
}
}
}
}
return $parsed_block;
}
add_filter( 'render_block_data', 'block_core_navigation_typographic_presets_backcompatibility' );
@@ -0,0 +1,124 @@
{
"apiVersion": 2,
"name": "core/navigation",
"title": "Navigation",
"category": "theme",
"description": "A collection of blocks that allow visitors to get around your site.",
"keywords": [
"menu",
"navigation",
"links"
],
"textdomain": "default",
"attributes": {
"navigationMenuId": {
"type": "number"
},
"textColor": {
"type": "string"
},
"customTextColor": {
"type": "string"
},
"rgbTextColor": {
"type": "string"
},
"backgroundColor": {
"type": "string"
},
"customBackgroundColor": {
"type": "string"
},
"rgbBackgroundColor": {
"type": "string"
},
"showSubmenuIcon": {
"type": "boolean",
"default": true
},
"openSubmenusOnClick": {
"type": "boolean",
"default": false
},
"overlayMenu": {
"type": "string",
"default": "mobile"
},
"__unstableLocation": {
"type": "string"
},
"overlayBackgroundColor": {
"type": "string"
},
"customOverlayBackgroundColor": {
"type": "string"
},
"overlayTextColor": {
"type": "string"
},
"customOverlayTextColor": {
"type": "string"
}
},
"usesContext": [ "navigationArea" ],
"providesContext": {
"textColor": "textColor",
"customTextColor": "customTextColor",
"backgroundColor": "backgroundColor",
"customBackgroundColor": "customBackgroundColor",
"overlayTextColor": "overlayTextColor",
"customOverlayTextColor": "customOverlayTextColor",
"overlayBackgroundColor": "overlayBackgroundColor",
"customOverlayBackgroundColor": "customOverlayBackgroundColor",
"fontSize": "fontSize",
"customFontSize": "customFontSize",
"showSubmenuIcon": "showSubmenuIcon",
"openSubmenusOnClick": "openSubmenusOnClick",
"style": "style",
"orientation": "orientation"
},
"supports": {
"align": [
"wide",
"full"
],
"anchor": true,
"html": false,
"inserter": true,
"typography": {
"fontSize": true,
"lineHeight": true,
"__experimentalFontStyle": true,
"__experimentalFontWeight": true,
"__experimentalTextTransform": true,
"__experimentalFontFamily": true,
"__experimentalTextDecoration": true,
"__experimentalDefaultControls": {
"fontSize": true
}
},
"spacing": {
"blockGap": true,
"units": [
"px",
"em",
"rem",
"vh",
"vw"
],
"__experimentalDefaultControls": {
"blockGap": true
}
},
"__experimentalLayout": {
"allowSwitching": false,
"allowInheriting": false,
"default": {
"type": "flex"
}
}
},
"viewScript": "file:./view.min.js",
"editorStyle": "wp-block-navigation-editor",
"style": "wp-block-navigation"
}
@@ -0,0 +1 @@
<?php return array('dependencies' => array(), 'version' => '86538493346805d860c94eb70dd1323d');
@@ -0,0 +1 @@
<?php return array('dependencies' => array(), 'version' => '7b2c5174a07c417dc3db6f1d9a9c3f78');
+44
View File
@@ -0,0 +1,44 @@
<?php
/**
* Server-side rendering of the `core/pattern` block.
*
* @package WordPress
*/
/**
* Registers the `core/pattern` block on the server.
*
* @return void
*/
function register_block_core_pattern() {
register_block_type_from_metadata(
__DIR__ . '/pattern',
array(
'render_callback' => 'render_block_core_pattern',
)
);
}
/**
* Renders the `core/pattern` block on the server.
*
* @param array $attributes Block attributes.
*
* @return string Returns the output of the pattern.
*/
function render_block_core_pattern( $attributes ) {
if ( empty( $attributes['slug'] ) ) {
return '';
}
$slug = $attributes['slug'];
$registry = WP_Block_Patterns_Registry::get_instance();
if ( ! $registry->is_registered( $slug ) ) {
return '';
}
$pattern = $registry->get_registered( $slug );
return do_blocks( $pattern['content'] );
}
add_action( 'init', 'register_block_core_pattern' );
+17
View File
@@ -0,0 +1,17 @@
{
"apiVersion": 2,
"name": "core/pattern",
"title": "Pattern",
"category": "design",
"description": "Show a block pattern.",
"supports": {
"html": false,
"inserter": false
},
"textdomain": "default",
"attributes": {
"slug": {
"type": "string"
}
}
}
+61
View File
@@ -0,0 +1,61 @@
<?php
/**
* Server-side rendering of the `core/post-author` block.
*
* @package WordPress
*/
/**
* Renders the `core/post-author` block on the server.
*
* @param array $attributes Block attributes.
* @param string $content Block default content.
* @param WP_Block $block Block instance.
* @return string Returns the rendered author block.
*/
function render_block_core_post_author( $attributes, $content, $block ) {
if ( ! isset( $block->context['postId'] ) ) {
return '';
}
$author_id = get_post_field( 'post_author', $block->context['postId'] );
if ( empty( $author_id ) ) {
return '';
}
$avatar = ! empty( $attributes['avatarSize'] ) ? get_avatar(
$author_id,
$attributes['avatarSize']
) : null;
$byline = ! empty( $attributes['byline'] ) ? $attributes['byline'] : false;
$classes = array_merge(
isset( $attributes['className'] ) ? array( $attributes['className'] ) : array(),
isset( $attributes['itemsJustification'] ) ? array( 'items-justified-' . $attributes['itemsJustification'] ) : array(),
isset( $attributes['textAlign'] ) ? array( 'has-text-align-' . $attributes['textAlign'] ) : array()
);
$wrapper_attributes = get_block_wrapper_attributes( array( 'class' => implode( ' ', $classes ) ) );
return sprintf( '<div %1$s>', $wrapper_attributes ) .
( ! empty( $attributes['showAvatar'] ) ? '<div class="wp-block-post-author__avatar">' . $avatar . '</div>' : '' ) .
'<div class="wp-block-post-author__content">' .
( ! empty( $byline ) ? '<p class="wp-block-post-author__byline">' . $byline . '</p>' : '' ) .
'<p class="wp-block-post-author__name">' . get_the_author_meta( 'display_name', $author_id ) . '</p>' .
( ! empty( $attributes['showBio'] ) ? '<p class="wp-block-post-author__bio">' . get_the_author_meta( 'user_description', $author_id ) . '</p>' : '' ) .
'</div>' .
'</div>';
}
/**
* Registers the `core/post-author` block on the server.
*/
function register_block_core_post_author() {
register_block_type_from_metadata(
__DIR__ . '/post-author',
array(
'render_callback' => 'render_block_core_post_author',
)
);
}
add_action( 'init', 'register_block_core_post_author' );
@@ -0,0 +1,53 @@
{
"apiVersion": 2,
"name": "core/post-author",
"title": "Post Author",
"category": "theme",
"description": "Add the author of this post.",
"textdomain": "default",
"attributes": {
"textAlign": {
"type": "string"
},
"avatarSize": {
"type": "number",
"default": 48
},
"showAvatar": {
"type": "boolean",
"default": true
},
"showBio": {
"type": "boolean"
},
"byline": {
"type": "string"
}
},
"usesContext": [ "postType", "postId", "queryId" ],
"supports": {
"html": false,
"spacing": {
"margin": true,
"padding": true
},
"typography": {
"fontSize": true,
"lineHeight": true,
"__experimentalFontStyle": true,
"__experimentalFontWeight": true,
"__experimentalLetterSpacing": true,
"__experimentalTextTransform": true,
"__experimentalDefaultControls": {
"fontSize": true
}
},
"color": {
"gradients": true,
"link": true,
"__experimentalDuotone": ".wp-block-post-author__avatar img"
}
},
"editorStyle": "wp-block-post-author-editor",
"style": "wp-block-post-author"
}
+68
View File
@@ -0,0 +1,68 @@
<?php
/**
* Server-side rendering of the `core/post-comments` block.
*
* @package WordPress
*/
/**
* Renders the `core/post-comments` block on the server.
*
* @param array $attributes Block attributes.
* @param string $content Block default content.
* @param WP_Block $block Block instance.
* @return string Returns the filtered post comments for the current post wrapped inside "p" tags.
*/
function render_block_core_post_comments( $attributes, $content, $block ) {
global $post;
$post_id = $block->context['postId'];
if ( ! isset( $post_id ) ) {
return '';
}
$comment_args = array(
'post_id' => $post_id,
'count' => true,
);
// Return early if there are no comments and comments are closed.
if ( ! comments_open( $post_id ) && get_comments( $comment_args ) === 0 ) {
return '';
}
$post_before = $post;
$post = get_post( $post_id );
setup_postdata( $post );
ob_start();
// There's a deprecation warning generated by WP Core.
// Ideally this deprecation is removed from Core.
// In the meantime, this removes it from the output.
add_filter( 'deprecated_file_trigger_error', '__return_false' );
comments_template();
remove_filter( 'deprecated_file_trigger_error', '__return_false' );
$post = $post_before;
$classes = '';
if ( isset( $attributes['textAlign'] ) ) {
$classes .= 'has-text-align-' . $attributes['textAlign'];
}
$wrapper_attributes = get_block_wrapper_attributes( array( 'class' => $classes ) );
$output = ob_get_clean();
return sprintf( '<div %1$s>%2$s</div>', $wrapper_attributes, $output );
}
/**
* Registers the `core/post-comments` block on the server.
*/
function register_block_core_post_comments() {
register_block_type_from_metadata(
__DIR__ . '/post-comments',
array(
'render_callback' => 'render_block_core_post_comments',
)
);
}
add_action( 'init', 'register_block_core_post_comments' );
@@ -0,0 +1,34 @@
{
"apiVersion": 2,
"name": "core/post-comments",
"title": "Post Comments",
"category": "theme",
"description": "Display a post's comments.",
"textdomain": "default",
"attributes": {
"textAlign": {
"type": "string"
}
},
"usesContext": [ "postId", "postType" ],
"supports": {
"html": false,
"align": [ "wide", "full" ],
"typography": {
"fontSize": true,
"lineHeight": true,
"__experimentalFontStyle": true,
"__experimentalFontWeight": true,
"__experimentalLetterSpacing": true,
"__experimentalTextTransform": true,
"__experimentalDefaultControls": {
"fontSize": true
}
},
"color": {
"gradients": true,
"link": true
}
},
"style": "wp-block-post-comments"
}
@@ -0,0 +1,96 @@
<?php
/**
* Server-side rendering of the `core/post-navigation-link` block.
*
* @package WordPress
*/
/**
* Renders the `core/post-navigation-link` block on the server.
*
* @param array $attributes Block attributes.
* @param string $content Block default content.
*
* @return string Returns the next or previous post link that is adjacent to the current post.
*/
function render_block_core_post_navigation_link( $attributes, $content ) {
if ( ! is_singular() ) {
return '';
}
// Get the nagigation type to show the proper link. Available options are `next|previous`.
$navigation_type = isset( $attributes['type'] ) ? $attributes['type'] : 'next';
// Allow only `next` and `previous` in `$navigation_type`.
if ( ! in_array( $navigation_type, array( 'next', 'previous' ), true ) ) {
return '';
}
$classes = "post-navigation-link-$navigation_type";
if ( isset( $attributes['textAlign'] ) ) {
$classes .= " has-text-align-{$attributes['textAlign']}";
}
$wrapper_attributes = get_block_wrapper_attributes( array( 'class' => $classes ) );
// Set default values.
$format = '%link';
$link = 'next' === $navigation_type ? _x( 'Next', 'label for next post link' ) : _x( 'Previous', 'label for previous post link' );
$label = '';
// If a custom label is provided, make this a link.
// `$label` is used to prepend the provided label, if we want to show the page title as well.
if ( isset( $attributes['label'] ) && ! empty( $attributes['label'] ) ) {
$label = "{$attributes['label']}";
$link = $label;
}
// If we want to also show the page title, make the page title a link and prepend the label.
if ( isset( $attributes['showTitle'] ) && $attributes['showTitle'] ) {
/*
* If the label link option is not enabled but there is a custom label,
* display the custom label as text before the linked title.
*/
if ( ! $attributes['linkLabel'] ) {
if ( $label ) {
$format = '<span class="post-navigation-link__label">' . $label . '</span> %link';
}
$link = '%title';
} elseif ( isset( $attributes['linkLabel'] ) && $attributes['linkLabel'] ) {
// If the label link option is enabled and there is a custom label, display it before the title.
if ( $label ) {
$link = '<span class="post-navigation-link__label">' . $label . '</span> <span class="post-navigation-link__title">%title</title>';
} else {
/*
* If the label link option is enabled and there is no custom label,
* add a colon between the label and the post title.
*/
$label = 'next' === $navigation_type ? _x( 'Next:', 'label before the title of the next post' ) : _x( 'Previous:', 'label before the title of the previous post' );
$link = sprintf(
'<span class="post-navigation-link__label">%1$s</span> <span class="post-navigation-link__title">%2$s</span>',
$label,
'%title'
);
}
}
}
// The dynamic portion of the function name, `$navigation_type`,
// refers to the type of adjacency, 'next' or 'previous'.
$get_link_function = "get_{$navigation_type}_post_link";
$content = $get_link_function( $format, $link );
return sprintf(
'<div %1$s>%2$s</div>',
$wrapper_attributes,
$content
);
}
/**
* Registers the `core/post-navigation-link` block on the server.
*/
function register_block_core_post_navigation_link() {
register_block_type_from_metadata(
__DIR__ . '/post-navigation-link',
array(
'render_callback' => 'render_block_core_post_navigation_link',
)
);
}
add_action( 'init', 'register_block_core_post_navigation_link' );
@@ -0,0 +1,43 @@
{
"apiVersion": 2,
"name": "core/post-navigation-link",
"title": "Post Navigation Link",
"category": "theme",
"description": "Displays the next or previous post link that is adjacent to the current post.",
"textdomain": "default",
"attributes": {
"textAlign": {
"type": "string"
},
"type": {
"type": "string",
"default": "next"
},
"label": {
"type": "string"
},
"showTitle": {
"type": "boolean",
"default": false
},
"linkLabel": {
"type": "boolean",
"default": false
}
},
"supports": {
"reusable": false,
"html": false,
"typography": {
"fontSize": true,
"lineHeight": true,
"__experimentalFontStyle": true,
"__experimentalFontWeight": true,
"__experimentalLetterSpacing": true,
"__experimentalTextTransform": true,
"__experimentalDefaultControls": {
"fontSize": true
}
}
}
}
@@ -0,0 +1,45 @@
<?php
/**
* Server-side rendering of the `core/term-description` block.
*
* @package WordPress
*/
/**
* Renders the `core/term-description` block on the server.
*
* @param array $attributes Block attributes.
*
* @return string Returns the description of the current taxonomy term, if available
*/
function render_block_core_term_description( $attributes ) {
$term_description = '';
if ( is_category() || is_tag() || is_tax() ) {
$term_description = term_description();
}
if ( empty( $term_description ) ) {
return '';
}
$extra_attributes = ( isset( $attributes['textAlign'] ) )
? array( 'class' => 'has-text-align-' . $attributes['textAlign'] )
: array();
$wrapper_attributes = get_block_wrapper_attributes( $extra_attributes );
return '<div ' . $wrapper_attributes . '>' . $term_description . '</div>';
}
/**
* Registers the `core/term-description` block on the server.
*/
function register_block_core_term_description() {
register_block_type_from_metadata(
__DIR__ . '/term-description',
array(
'render_callback' => 'render_block_core_term_description',
)
);
}
add_action( 'init', 'register_block_core_term_description' );
@@ -0,0 +1,28 @@
{
"apiVersion": 2,
"name": "core/term-description",
"title": "Term Description",
"category": "theme",
"description": "Display the description of categories, tags and custom taxonomies when viewing an archive.",
"textdomain": "default",
"attributes": {
"textAlign": {
"type": "string"
}
},
"supports": {
"align": [ "wide", "full" ],
"html": false,
"color": {
"link": true
},
"typography": {
"fontSize": true,
"lineHeight": true,
"__experimentalDefaultControls": {
"fontSize": true
}
}
},
"editorStyle": "wp-block-term-description-editor"
}
+78
View File
@@ -0,0 +1,78 @@
<?php
/**
* Server-side rendering of the `core/widget-group` block.
*
* @package WordPress
*/
/**
* Renders the 'core/widget-group' block.
*
* @param array $attributes The block attributes.
* @param string $content The block content.
* @param WP_Block $block The block.
*
* @return string Rendered block.
*/
function render_block_core_widget_group( $attributes, $content, $block ) {
global $wp_registered_sidebars, $_sidebar_being_rendered;
if ( isset( $wp_registered_sidebars[ $_sidebar_being_rendered ] ) ) {
$before_title = $wp_registered_sidebars[ $_sidebar_being_rendered ]['before_title'];
$after_title = $wp_registered_sidebars[ $_sidebar_being_rendered ]['after_title'];
} else {
$before_title = '<h2 class="widget-title">';
$after_title = '</h2>';
}
$html = '';
if ( ! empty( $attributes['title'] ) ) {
$html .= $before_title . $attributes['title'] . $after_title;
}
$html .= '<div class="wp-widget-group__inner-blocks">';
foreach ( $block->inner_blocks as $inner_block ) {
$html .= $inner_block->render();
}
$html .= '</div>';
return $html;
}
/**
* Registers the 'core/widget-group' block.
*/
function register_block_core_widget_group() {
register_block_type_from_metadata(
__DIR__ . '/widget-group',
array(
'render_callback' => 'render_block_core_widget_group',
)
);
}
add_action( 'init', 'register_block_core_widget_group' );
/**
* Make a note of the sidebar being rendered before WordPress starts rendering
* it. This lets us get to the current sidebar in
* render_block_core_widget_group().
*
* @param int|string $index Index, name, or ID of the dynamic sidebar.
*/
function note_sidebar_being_rendered( $index ) {
global $_sidebar_being_rendered;
$_sidebar_being_rendered = $index;
}
add_action( 'dynamic_sidebar_before', 'note_sidebar_being_rendered' );
/**
* Clear whatever we set in note_sidebar_being_rendered() after WordPress
* finishes rendering a sidebar.
*/
function discard_sidebar_being_rendered() {
global $_sidebar_being_rendered;
unset( $_sidebar_being_rendered );
}
add_action( 'dynamic_sidebar_after', 'discard_sidebar_being_rendered' );
@@ -0,0 +1,18 @@
{
"apiVersion": 2,
"name": "core/widget-group",
"category": "widgets",
"attributes": {
"title": {
"type": "string"
}
},
"supports": {
"html": false,
"inserter": true,
"customClassName": true,
"reusable": false
},
"editorStyle": "wp-block-widget-group-editor",
"style": "wp-block-widget-group"
}