page-list.php (7259B)
1 <?php 2 /** 3 * Server-side rendering of the `core/pages` block. 4 * 5 * @package WordPress 6 */ 7 8 /** 9 * Build an array with CSS classes and inline styles defining the colors 10 * which will be applied to the pages markup in the front-end when it is a descendant of navigation. 11 * 12 * @param array $context Navigation block context. 13 * @return array Colors CSS classes and inline styles. 14 */ 15 function block_core_page_list_build_css_colors( $context ) { 16 $colors = array( 17 'css_classes' => array(), 18 'inline_styles' => '', 19 ); 20 21 // Text color. 22 $has_named_text_color = array_key_exists( 'textColor', $context ); 23 $has_custom_text_color = isset( $context['style']['color']['text'] ); 24 25 // If has text color. 26 if ( $has_custom_text_color || $has_named_text_color ) { 27 // Add has-text-color class. 28 $colors['css_classes'][] = 'has-text-color'; 29 } 30 31 if ( $has_named_text_color ) { 32 // Add the color class. 33 $colors['css_classes'][] = sprintf( 'has-%s-color', $context['textColor'] ); 34 } elseif ( $has_custom_text_color ) { 35 // Add the custom color inline style. 36 $colors['inline_styles'] .= sprintf( 'color: %s;', $context['style']['color']['text'] ); 37 } 38 39 // Background color. 40 $has_named_background_color = array_key_exists( 'backgroundColor', $context ); 41 $has_custom_background_color = isset( $context['style']['color']['background'] ); 42 43 // If has background color. 44 if ( $has_custom_background_color || $has_named_background_color ) { 45 // Add has-background class. 46 $colors['css_classes'][] = 'has-background'; 47 } 48 49 if ( $has_named_background_color ) { 50 // Add the background-color class. 51 $colors['css_classes'][] = sprintf( 'has-%s-background-color', $context['backgroundColor'] ); 52 } elseif ( $has_custom_background_color ) { 53 // Add the custom background-color inline style. 54 $colors['inline_styles'] .= sprintf( 'background-color: %s;', $context['style']['color']['background'] ); 55 } 56 57 return $colors; 58 } 59 60 /** 61 * Build an array with CSS classes and inline styles defining the font sizes 62 * which will be applied to the pages markup in the front-end when it is a descendant of navigation. 63 * 64 * @param array $context Navigation block context. 65 * @return array Font size CSS classes and inline styles. 66 */ 67 function block_core_page_list_build_css_font_sizes( $context ) { 68 // CSS classes. 69 $font_sizes = array( 70 'css_classes' => array(), 71 'inline_styles' => '', 72 ); 73 74 $has_named_font_size = array_key_exists( 'fontSize', $context ); 75 $has_custom_font_size = isset( $context['style']['typography']['fontSize'] ); 76 77 if ( $has_named_font_size ) { 78 // Add the font size class. 79 $font_sizes['css_classes'][] = sprintf( 'has-%s-font-size', $context['fontSize'] ); 80 } elseif ( $has_custom_font_size ) { 81 // Add the custom font size inline style. 82 $font_sizes['inline_styles'] = sprintf( 'font-size: %spx;', $context['style']['typography']['fontSize'] ); 83 } 84 85 return $font_sizes; 86 } 87 88 /** 89 * Outputs Page list markup from an array of pages with nested children. 90 * 91 * @param array $nested_pages The array of nested pages. 92 * 93 * @return string List markup. 94 */ 95 function block_core_page_list_render_nested_page_list( $nested_pages ) { 96 if ( empty( $nested_pages ) ) { 97 return; 98 } 99 $markup = ''; 100 foreach ( (array) $nested_pages as $page ) { 101 $css_class = 'wp-block-pages-list__item'; 102 if ( isset( $page['children'] ) ) { 103 $css_class .= ' has-child'; 104 } 105 $markup .= '<li class="' . $css_class . '">'; 106 $markup .= '<a class="wp-block-pages-list__item__link" href="' . esc_url( $page['link'] ) . '">' . wp_kses( 107 $page['title'], 108 wp_kses_allowed_html( 'post' ) 109 ) . '</a>'; 110 if ( isset( $page['children'] ) ) { 111 $markup .= '<span class="wp-block-page-list__submenu-icon"><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></span>'; 112 $markup .= '<ul class="submenu-container">' . block_core_page_list_render_nested_page_list( $page['children'] ) . '</ul>'; 113 } 114 $markup .= '</li>'; 115 } 116 return $markup; 117 } 118 119 /** 120 * Outputs nested array of pages 121 * 122 * @param array $current_level The level being iterated through. 123 * @param array $children The children grouped by parent post ID. 124 * 125 * @return array The nested array of pages. 126 */ 127 function block_core_page_list_nest_pages( $current_level, $children ) { 128 if ( empty( $current_level ) ) { 129 return; 130 } 131 foreach ( (array) $current_level as $key => $current ) { 132 if ( isset( $children[ $key ] ) ) { 133 $current_level[ $key ]['children'] = block_core_page_list_nest_pages( $children[ $key ], $children ); 134 } 135 } 136 return $current_level; 137 } 138 139 /** 140 * Renders the `core/page-list` block on server. 141 * 142 * @param array $attributes The block attributes. 143 * @param array $content The saved content. 144 * @param array $block The parsed block. 145 * 146 * @return string Returns the page list markup. 147 */ 148 function render_block_core_page_list( $attributes, $content, $block ) { 149 static $block_id = 0; 150 $block_id++; 151 152 // TODO: When https://core.trac.wordpress.org/ticket/39037 REST API support for multiple orderby values is resolved, 153 // update 'sort_column' to 'menu_order, post_title'. Sorting by both menu_order and post_title ensures a stable sort. 154 // Otherwise with pages that have the same menu_order value, we can see different ordering depending on how DB 155 // queries are constructed internally. For example we might see a different order when a limit is set to <499 156 // versus >= 500. 157 $all_pages = get_pages( 158 array( 159 'sort_column' => 'menu_order', 160 'order' => 'asc', 161 ) 162 ); 163 164 $top_level_pages = array(); 165 166 $pages_with_children = array(); 167 168 foreach ( (array) $all_pages as $page ) { 169 if ( $page->post_parent ) { 170 $pages_with_children[ $page->post_parent ][ $page->ID ] = array( 171 'title' => $page->post_title, 172 'link' => get_permalink( $page->ID ), 173 ); 174 } else { 175 $top_level_pages[ $page->ID ] = array( 176 'title' => $page->post_title, 177 'link' => get_permalink( $page->ID ), 178 ); 179 180 } 181 } 182 183 $nested_pages = block_core_page_list_nest_pages( $top_level_pages, $pages_with_children ); 184 185 $wrapper_markup = '<ul %1$s>%2$s</ul>'; 186 187 $items_markup = block_core_page_list_render_nested_page_list( $nested_pages ); 188 189 $colors = block_core_page_list_build_css_colors( $block->context ); 190 $font_sizes = block_core_page_list_build_css_font_sizes( $block->context ); 191 $classes = array_merge( 192 $colors['css_classes'], 193 $font_sizes['css_classes'] 194 ); 195 $style_attribute = ( $colors['inline_styles'] . $font_sizes['inline_styles'] ); 196 $css_classes = trim( implode( ' ', $classes ) ); 197 198 if ( $block->context && $block->context['showSubmenuIcon'] ) { 199 $css_classes .= ' show-submenu-icons'; 200 } 201 202 $wrapper_attributes = get_block_wrapper_attributes( 203 array( 204 'class' => $css_classes, 205 'style' => $style_attribute, 206 ) 207 ); 208 209 return sprintf( 210 $wrapper_markup, 211 $wrapper_attributes, 212 $items_markup 213 ); 214 } 215 216 /** 217 * Registers the `core/pages` block on server. 218 */ 219 function register_block_core_page_list() { 220 register_block_type_from_metadata( 221 __DIR__ . '/page-list', 222 array( 223 'render_callback' => 'render_block_core_page_list', 224 ) 225 ); 226 } 227 add_action( 'init', 'register_block_core_page_list' );