'after', 'anchor' => 'core/navigation', 'area' => 'header', 'callback' => 'should_unhook_block', 'version' => '8.4.0', ), ); /** * Initialize this block type. */ protected function initialize() { parent::initialize(); /** * The hooked_block_{$hooked_block_type} filter was added in WordPress 6.5. * We are the only code adding the filter 'hooked_block_woocommerce/customer-account'. * Using has_filter() for a compatibility check won't work because add_filter() is used in the same file. */ if ( version_compare( get_bloginfo( 'version' ), '6.5', '>=' ) ) { add_filter( 'hooked_block_woocommerce/customer-account', array( $this, 'modify_hooked_block_attributes' ), 10, 5 ); add_filter( 'hooked_block_types', array( $this, 'register_hooked_block' ), 9, 4 ); } } /** * Callback for the Block Hooks API to modify the attributes of the hooked block. * * @param array|null $parsed_hooked_block The parsed block array for the given hooked block type, or null to suppress the block. * @param string $hooked_block_type The hooked block type name. * @param string $relative_position The relative position of the hooked block. * @param array $parsed_anchor_block The anchor block, in parsed block array format. * @param WP_Block_Template|WP_Post|array $context The block template, template part, `wp_navigation` post type, * or pattern that the anchor block belongs to. * @return array|null */ public function modify_hooked_block_attributes( $parsed_hooked_block, $hooked_block_type, $relative_position, $parsed_anchor_block, $context ) { $parsed_hooked_block['attrs']['displayStyle'] = 'icon_only'; $parsed_hooked_block['attrs']['iconStyle'] = 'line'; $parsed_hooked_block['attrs']['iconClass'] = 'wc-block-customer-account__account-icon'; $customer_account_block_font_size = wp_get_global_styles( array( 'blocks', 'woocommerce/customer-account', 'typography', 'fontSize' ) ); if ( ! is_string( $customer_account_block_font_size ) ) { $navigation_block_font_size = wp_get_global_styles( array( 'blocks', 'core/navigation', 'typography', 'fontSize' ) ); if ( is_string( $navigation_block_font_size ) ) { $parsed_hooked_block['attrs']['style']['typography']['fontSize'] = $navigation_block_font_size; } } return $parsed_hooked_block; } /** * Callback for the Block Hooks API to determine if the block should be auto-inserted. * * @param array $hooked_blocks An array of block slugs hooked into a given context. * @param string $position Position of the block insertion point. * @param string $anchor_block The block acting as the anchor for the inserted block. * @param array|\WP_Post|\WP_Block_Template $context Where the block is embedded. * * @return array */ protected function should_unhook_block( $hooked_blocks, $position, $anchor_block, $context ) { $block_name = $this->namespace . '/' . $this->block_name; $block_is_hooked = in_array( $block_name, $hooked_blocks, true ); if ( $block_is_hooked ) { $active_theme = wp_get_theme()->get( 'Name' ); $exclude_themes = array( 'Twenty Twenty-Two', 'Twenty Twenty-Three' ); if ( in_array( $active_theme, $exclude_themes, true ) ) { $key = array_search( $block_name, $hooked_blocks, true ); unset( $hooked_blocks[ $key ] ); } } return $hooked_blocks; } /** * Render the block. * * @param array $attributes Block attributes. * @param string $content Block content. * @param WP_Block $block Block instance. * * @return string Rendered block output. */ protected function render( $attributes, $content, $block ) { $classes_and_styles = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes ); $has_myaccount_page = get_option( 'woocommerce_myaccount_page_id' ); $account_link = $has_myaccount_page ? wc_get_account_endpoint_url( 'dashboard' ) : wp_login_url(); $has_dropdown = ! empty( $attributes['hasDropdownNavigation'] ) && is_user_logged_in() && $has_myaccount_page; $aria_label = self::ICON_ONLY === $attributes['displayStyle'] ? ' aria-label="' . esc_attr( $this->render_label() ) . '"' : ''; $label_markup = self::ICON_ONLY === $attributes['displayStyle'] ? '' : '' . wp_kses( $this->render_label(), array() ) . ''; if ( ! $has_dropdown ) { return $this->render_link( $attributes, $classes_and_styles, $account_link, $aria_label, $label_markup ); } return $this->render_dropdown( $attributes, $classes_and_styles, $aria_label, $label_markup ); } /** * Render the block as a simple link (default behavior). * * @param array $attributes Block attributes. * @param array $classes_and_styles Classes and styles from block attributes. * @param string $account_link URL to link to. * @param string $aria_label Pre-computed aria-label attribute string. * @param string $label_markup Pre-computed label HTML markup. * * @return string Rendered block output. */ private function render_link( $attributes, $classes_and_styles, $account_link, $aria_label, $label_markup ) { ob_start(); ?>
> render_visual( $attributes ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
false, 'showAbove' => false, 'alignRight' => false, ); $menu_items = wc_get_account_menu_items(); $dropdown_html = $this->render_dropdown_menu( $menu_items ); ob_start(); ?>
data-wp-class--wc-block-customer-account--align-right="context.alignRight" data-wp-class--wc-block-customer-account--is-dropdown-open="context.isDropdownOpen" data-wp-class--wc-block-customer-account--show-above="context.showAbove" data-wp-on--focusout="actions.handleFocusOut" data-wp-on-document--click="actions.handleDocumentClick" data-wp-on-document--keydown="actions.handleKeydown" >
render_section( array( 'dashboard' => $menu_items['dashboard'] ) ); } $nav_items = array_diff_key( $menu_items, array_flip( array( 'dashboard', 'customer-logout' ) ) ); if ( ! empty( $nav_items ) ) { $sections[] = $this->render_section( $nav_items ); } if ( isset( $menu_items['customer-logout'] ) ) { $sections[] = $this->render_section( array( 'customer-logout' => $menu_items['customer-logout'] ) ); } return implode( '
', $sections ); } /** * Render a dropdown section wrapping one or more menu items. * * @param array $items Associative array of endpoint => label pairs. * * @return string Rendered section HTML. */ private function render_section( $items ) { $output = '
'; foreach ( $items as $endpoint => $label ) { $output .= $this->render_menu_item( $endpoint, $label ); } $output .= '
'; return $output; } /** * Render a single dropdown menu item. * * @param string $endpoint The account endpoint key. * @param string $label The menu item label. * * @return string Rendered menu item HTML. */ private function render_menu_item( $endpoint, $label ) { $url = wc_get_account_endpoint_url( $endpoint ); return '' . esc_html( $label ) . ''; } /** * Render the caret/chevron icon for the dropdown toggle. * * @return string SVG markup for the caret icon. */ private function render_caret_icon() { return ' '; } /** * Gets the icon to render depending on the iconStyle and displayStyle. * * @param array $attributes Block attributes. * * @return string SVG icon markup. */ private function render_icon( $attributes ) { if ( self::TEXT_ONLY === $attributes['displayStyle'] ) { return ''; } if ( self::DISPLAY_LINE === $attributes['iconStyle'] ) { return ' '; } if ( self::DISPLAY_ALT === $attributes['iconStyle'] ) { return ' '; } return ' '; } /** * Render the user avatar and icon. * * @param array $attributes Block attributes. * * @return string Avatar and icon markup. */ private function render_visual( $attributes ) { if ( self::TEXT_ONLY === $attributes['displayStyle'] ) { return ''; } $icon = $this->render_icon( $attributes ); $user_id = get_current_user_id(); if ( $user_id ) { // We use `blank` as the default so if the user has no avatar, the icon underneath is visible. $avatar = get_avatar( $user_id, 48, 'blank', '', array( 'class' => 'wc-block-customer-account__avatar', ) ); if ( $avatar ) { return '
' . $icon . wp_kses_post( $avatar ) . '
'; } } return '
' . $icon . '
'; } /** * Gets the label to render depending on the displayStyle. * * @return string Label to render on the block. */ private function render_label() { return get_current_user_id() ? __( 'My Account', 'woocommerce' ) : __( 'Login', 'woocommerce' ); } }